xref: /minix/external/bsd/nvi/dist/vi/v_itxt.c (revision 0a6a1f1d)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: v_itxt.c,v 1.3 2014/01/26 21:43:45 christos Exp $	*/
284d9c625SLionel Sambuc /*-
384d9c625SLionel Sambuc  * Copyright (c) 1992, 1993, 1994
484d9c625SLionel Sambuc  *	The Regents of the University of California.  All rights reserved.
584d9c625SLionel Sambuc  * Copyright (c) 1992, 1993, 1994, 1995, 1996
684d9c625SLionel Sambuc  *	Keith Bostic.  All rights reserved.
784d9c625SLionel Sambuc  *
884d9c625SLionel Sambuc  * See the LICENSE file for redistribution information.
984d9c625SLionel Sambuc  */
1084d9c625SLionel Sambuc 
1184d9c625SLionel Sambuc #include "config.h"
1284d9c625SLionel Sambuc 
13*0a6a1f1dSLionel Sambuc #include <sys/cdefs.h>
14*0a6a1f1dSLionel Sambuc #if 0
1584d9c625SLionel Sambuc #ifndef lint
1684d9c625SLionel Sambuc static const char sccsid[] = "Id: v_itxt.c,v 10.21 2001/06/25 15:19:32 skimo Exp  (Berkeley) Date: 2001/06/25 15:19:32 ";
1784d9c625SLionel Sambuc #endif /* not lint */
18*0a6a1f1dSLionel Sambuc #else
19*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: v_itxt.c,v 1.3 2014/01/26 21:43:45 christos Exp $");
20*0a6a1f1dSLionel Sambuc #endif
2184d9c625SLionel Sambuc 
2284d9c625SLionel Sambuc #include <sys/types.h>
2384d9c625SLionel Sambuc #include <sys/queue.h>
2484d9c625SLionel Sambuc #include <sys/time.h>
2584d9c625SLionel Sambuc 
2684d9c625SLionel Sambuc #include <bitstring.h>
2784d9c625SLionel Sambuc #include <ctype.h>
2884d9c625SLionel Sambuc #include <errno.h>
2984d9c625SLionel Sambuc #include <limits.h>
3084d9c625SLionel Sambuc #include <stdio.h>
3184d9c625SLionel Sambuc #include <stdlib.h>
3284d9c625SLionel Sambuc #include <string.h>
3384d9c625SLionel Sambuc 
3484d9c625SLionel Sambuc #include "../common/common.h"
3584d9c625SLionel Sambuc #include "vi.h"
3684d9c625SLionel Sambuc 
3784d9c625SLionel Sambuc /*
3884d9c625SLionel Sambuc  * !!!
3984d9c625SLionel Sambuc  * Repeated input in the historic vi is mostly wrong and this isn't very
4084d9c625SLionel Sambuc  * backward compatible.  For example, if the user entered "3Aab\ncd" in
4184d9c625SLionel Sambuc  * the historic vi, the "ab" was repeated 3 times, and the "\ncd" was then
4284d9c625SLionel Sambuc  * appended to the result.  There was also a hack which I don't remember
4384d9c625SLionel Sambuc  * right now, where "3o" would open 3 lines and then let the user fill them
4484d9c625SLionel Sambuc  * in, to make screen movements on 300 baud modems more tolerable.  I don't
4584d9c625SLionel Sambuc  * think it's going to be missed.
4684d9c625SLionel Sambuc  *
4784d9c625SLionel Sambuc  * !!!
4884d9c625SLionel Sambuc  * There's a problem with the way that we do logging for change commands with
4984d9c625SLionel Sambuc  * implied motions (e.g. A, I, O, cc, etc.).  Since the main vi loop logs the
5084d9c625SLionel Sambuc  * starting cursor position before the change command "moves" the cursor, the
5184d9c625SLionel Sambuc  * cursor position to which we return on undo will be where the user entered
5284d9c625SLionel Sambuc  * the change command, not the start of the change.  Several of the following
5384d9c625SLionel Sambuc  * routines re-log the cursor to make this work correctly.  Historic vi tried
5484d9c625SLionel Sambuc  * to do the same thing, and mostly got it right.  (The only spectacular way
5584d9c625SLionel Sambuc  * it fails is if the user entered 'o' from anywhere but the last character of
5684d9c625SLionel Sambuc  * the line, the undo returned the cursor to the start of the line.  If the
5784d9c625SLionel Sambuc  * user was on the last character of the line, the cursor returned to that
5884d9c625SLionel Sambuc  * position.)  We also check for mapped keys waiting, i.e. if we're in the
5984d9c625SLionel Sambuc  * middle of a map, don't bother logging the cursor.
6084d9c625SLionel Sambuc  */
6184d9c625SLionel Sambuc #define	LOG_CORRECT {							\
6284d9c625SLionel Sambuc 	if (!MAPPED_KEYS_WAITING(sp))					\
6384d9c625SLionel Sambuc 		(void)log_cursor(sp);					\
6484d9c625SLionel Sambuc }
6584d9c625SLionel Sambuc 
6684d9c625SLionel Sambuc static u_int32_t set_txt_std __P((SCR *, VICMD *, u_int32_t));
6784d9c625SLionel Sambuc 
6884d9c625SLionel Sambuc /*
6984d9c625SLionel Sambuc  * v_iA -- [count]A
7084d9c625SLionel Sambuc  *	Append text to the end of the line.
7184d9c625SLionel Sambuc  *
7284d9c625SLionel Sambuc  * PUBLIC: int v_iA __P((SCR *, VICMD *));
7384d9c625SLionel Sambuc  */
7484d9c625SLionel Sambuc int
v_iA(SCR * sp,VICMD * vp)7584d9c625SLionel Sambuc v_iA(SCR *sp, VICMD *vp)
7684d9c625SLionel Sambuc {
7784d9c625SLionel Sambuc 	size_t len;
7884d9c625SLionel Sambuc 
7984d9c625SLionel Sambuc 	if (!db_get(sp, vp->m_start.lno, 0, NULL, &len))
8084d9c625SLionel Sambuc 		sp->cno = len == 0 ? 0 : len - 1;
8184d9c625SLionel Sambuc 
8284d9c625SLionel Sambuc 	LOG_CORRECT;
8384d9c625SLionel Sambuc 
8484d9c625SLionel Sambuc 	return (v_ia(sp, vp));
8584d9c625SLionel Sambuc }
8684d9c625SLionel Sambuc 
8784d9c625SLionel Sambuc /*
8884d9c625SLionel Sambuc  * v_ia -- [count]a
8984d9c625SLionel Sambuc  *	   [count]A
9084d9c625SLionel Sambuc  *	Append text to the cursor position.
9184d9c625SLionel Sambuc  *
9284d9c625SLionel Sambuc  * PUBLIC: int v_ia __P((SCR *, VICMD *));
9384d9c625SLionel Sambuc  */
9484d9c625SLionel Sambuc int
v_ia(SCR * sp,VICMD * vp)9584d9c625SLionel Sambuc v_ia(SCR *sp, VICMD *vp)
9684d9c625SLionel Sambuc {
9784d9c625SLionel Sambuc 	size_t len;
9884d9c625SLionel Sambuc 	u_int32_t flags;
9984d9c625SLionel Sambuc 	int isempty;
10084d9c625SLionel Sambuc 	CHAR_T *p;
10184d9c625SLionel Sambuc 
10284d9c625SLionel Sambuc 	flags = set_txt_std(sp, vp, 0);
10384d9c625SLionel Sambuc 	sp->showmode = SM_APPEND;
10484d9c625SLionel Sambuc 	sp->lno = vp->m_start.lno;
10584d9c625SLionel Sambuc 
10684d9c625SLionel Sambuc 	/* Move the cursor one column to the right and repaint the screen. */
10784d9c625SLionel Sambuc 	if (db_eget(sp, sp->lno, &p, &len, &isempty)) {
10884d9c625SLionel Sambuc 		if (!isempty)
10984d9c625SLionel Sambuc 			return (1);
11084d9c625SLionel Sambuc 		len = 0;
11184d9c625SLionel Sambuc 		LF_SET(TXT_APPENDEOL);
11284d9c625SLionel Sambuc 	} else if (len) {
11384d9c625SLionel Sambuc 		if (len == sp->cno + 1) {
11484d9c625SLionel Sambuc 			sp->cno = len;
11584d9c625SLionel Sambuc 			LF_SET(TXT_APPENDEOL);
11684d9c625SLionel Sambuc 		} else
11784d9c625SLionel Sambuc 			++sp->cno;
11884d9c625SLionel Sambuc 	} else
11984d9c625SLionel Sambuc 		LF_SET(TXT_APPENDEOL);
12084d9c625SLionel Sambuc 
12184d9c625SLionel Sambuc 	return (v_txt(sp, vp, NULL, p, len,
12284d9c625SLionel Sambuc 	    0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags));
12384d9c625SLionel Sambuc }
12484d9c625SLionel Sambuc 
12584d9c625SLionel Sambuc /*
12684d9c625SLionel Sambuc  * v_iI -- [count]I
12784d9c625SLionel Sambuc  *	Insert text at the first nonblank.
12884d9c625SLionel Sambuc  *
12984d9c625SLionel Sambuc  * PUBLIC: int v_iI __P((SCR *, VICMD *));
13084d9c625SLionel Sambuc  */
13184d9c625SLionel Sambuc int
v_iI(SCR * sp,VICMD * vp)13284d9c625SLionel Sambuc v_iI(SCR *sp, VICMD *vp)
13384d9c625SLionel Sambuc {
13484d9c625SLionel Sambuc 	sp->cno = 0;
13584d9c625SLionel Sambuc 	if (nonblank(sp, vp->m_start.lno, &sp->cno))
13684d9c625SLionel Sambuc 		return (1);
13784d9c625SLionel Sambuc 
13884d9c625SLionel Sambuc 	LOG_CORRECT;
13984d9c625SLionel Sambuc 
14084d9c625SLionel Sambuc 	return (v_ii(sp, vp));
14184d9c625SLionel Sambuc }
14284d9c625SLionel Sambuc 
14384d9c625SLionel Sambuc /*
14484d9c625SLionel Sambuc  * v_ii -- [count]i
14584d9c625SLionel Sambuc  *	   [count]I
14684d9c625SLionel Sambuc  *	Insert text at the cursor position.
14784d9c625SLionel Sambuc  *
14884d9c625SLionel Sambuc  * PUBLIC: int v_ii __P((SCR *, VICMD *));
14984d9c625SLionel Sambuc  */
15084d9c625SLionel Sambuc int
v_ii(SCR * sp,VICMD * vp)15184d9c625SLionel Sambuc v_ii(SCR *sp, VICMD *vp)
15284d9c625SLionel Sambuc {
15384d9c625SLionel Sambuc 	size_t len;
15484d9c625SLionel Sambuc 	u_int32_t flags;
15584d9c625SLionel Sambuc 	int isempty;
15684d9c625SLionel Sambuc 	CHAR_T *p;
15784d9c625SLionel Sambuc 
15884d9c625SLionel Sambuc 	flags = set_txt_std(sp, vp, 0);
15984d9c625SLionel Sambuc 	sp->showmode = SM_INSERT;
16084d9c625SLionel Sambuc 	sp->lno = vp->m_start.lno;
16184d9c625SLionel Sambuc 
16284d9c625SLionel Sambuc 	if (db_eget(sp, sp->lno, &p, &len, &isempty)) {
16384d9c625SLionel Sambuc 		if (!isempty)
16484d9c625SLionel Sambuc 			return (1);
16584d9c625SLionel Sambuc 		len = 0;
16684d9c625SLionel Sambuc 	}
16784d9c625SLionel Sambuc 
16884d9c625SLionel Sambuc 	if (len == 0)
16984d9c625SLionel Sambuc 		LF_SET(TXT_APPENDEOL);
17084d9c625SLionel Sambuc 	return (v_txt(sp, vp, NULL, p, len,
17184d9c625SLionel Sambuc 	    0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags));
17284d9c625SLionel Sambuc }
17384d9c625SLionel Sambuc 
17484d9c625SLionel Sambuc enum which { o_cmd, O_cmd };
17584d9c625SLionel Sambuc static int io __P((SCR *, VICMD *, enum which));
17684d9c625SLionel Sambuc 
17784d9c625SLionel Sambuc /*
17884d9c625SLionel Sambuc  * v_iO -- [count]O
17984d9c625SLionel Sambuc  *	Insert text above this line.
18084d9c625SLionel Sambuc  *
18184d9c625SLionel Sambuc  * PUBLIC: int v_iO __P((SCR *, VICMD *));
18284d9c625SLionel Sambuc  */
18384d9c625SLionel Sambuc int
v_iO(SCR * sp,VICMD * vp)18484d9c625SLionel Sambuc v_iO(SCR *sp, VICMD *vp)
18584d9c625SLionel Sambuc {
18684d9c625SLionel Sambuc 	return (io(sp, vp, O_cmd));
18784d9c625SLionel Sambuc }
18884d9c625SLionel Sambuc 
18984d9c625SLionel Sambuc /*
19084d9c625SLionel Sambuc  * v_io -- [count]o
19184d9c625SLionel Sambuc  *	Insert text after this line.
19284d9c625SLionel Sambuc  *
19384d9c625SLionel Sambuc  * PUBLIC: int v_io __P((SCR *, VICMD *));
19484d9c625SLionel Sambuc  */
19584d9c625SLionel Sambuc int
v_io(SCR * sp,VICMD * vp)19684d9c625SLionel Sambuc v_io(SCR *sp, VICMD *vp)
19784d9c625SLionel Sambuc {
19884d9c625SLionel Sambuc 	return (io(sp, vp, o_cmd));
19984d9c625SLionel Sambuc }
20084d9c625SLionel Sambuc 
20184d9c625SLionel Sambuc static int
io(SCR * sp,VICMD * vp,enum which cmd)20284d9c625SLionel Sambuc io(SCR *sp, VICMD *vp, enum which cmd)
20384d9c625SLionel Sambuc {
20484d9c625SLionel Sambuc 	db_recno_t ai_line, lno;
20584d9c625SLionel Sambuc 	size_t len;
20684d9c625SLionel Sambuc 	u_int32_t flags;
20784d9c625SLionel Sambuc 	CHAR_T *p;
20884d9c625SLionel Sambuc 
20984d9c625SLionel Sambuc 	flags = set_txt_std(sp, vp, TXT_ADDNEWLINE | TXT_APPENDEOL);
21084d9c625SLionel Sambuc 	sp->showmode = SM_INSERT;
21184d9c625SLionel Sambuc 
21284d9c625SLionel Sambuc 	if (sp->lno == 1) {
21384d9c625SLionel Sambuc 		if (db_last(sp, &lno))
21484d9c625SLionel Sambuc 			return (1);
21584d9c625SLionel Sambuc 		if (lno != 0)
21684d9c625SLionel Sambuc 			goto insert;
21784d9c625SLionel Sambuc 		p = NULL;
21884d9c625SLionel Sambuc 		len = 0;
21984d9c625SLionel Sambuc 		ai_line = OOBLNO;
22084d9c625SLionel Sambuc 	} else {
22184d9c625SLionel Sambuc 		static CHAR_T nul = 0;
22284d9c625SLionel Sambuc insert:		p = &nul;
22384d9c625SLionel Sambuc 		sp->cno = 0;
22484d9c625SLionel Sambuc 		LOG_CORRECT;
22584d9c625SLionel Sambuc 
22684d9c625SLionel Sambuc 		if (cmd == O_cmd) {
22784d9c625SLionel Sambuc 			if (db_insert(sp, sp->lno, p, 0))
22884d9c625SLionel Sambuc 				return (1);
22984d9c625SLionel Sambuc 			if (db_get(sp, sp->lno, DBG_FATAL, &p, &len))
23084d9c625SLionel Sambuc 				return (1);
23184d9c625SLionel Sambuc 			ai_line = sp->lno + 1;
23284d9c625SLionel Sambuc 		} else {
23384d9c625SLionel Sambuc 			if (db_append(sp, 1, sp->lno, p, 0))
23484d9c625SLionel Sambuc 				return (1);
23584d9c625SLionel Sambuc 			if (db_get(sp, ++sp->lno, DBG_FATAL, &p, &len))
23684d9c625SLionel Sambuc 				return (1);
23784d9c625SLionel Sambuc 			ai_line = sp->lno - 1;
23884d9c625SLionel Sambuc 		}
23984d9c625SLionel Sambuc 	}
24084d9c625SLionel Sambuc 	return (v_txt(sp, vp, NULL, p, len,
24184d9c625SLionel Sambuc 	    0, ai_line, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags));
24284d9c625SLionel Sambuc }
24384d9c625SLionel Sambuc 
24484d9c625SLionel Sambuc /*
24584d9c625SLionel Sambuc  * v_change -- [buffer][count]c[count]motion
24684d9c625SLionel Sambuc  *	       [buffer][count]C
24784d9c625SLionel Sambuc  *	       [buffer][count]S
24884d9c625SLionel Sambuc  *	Change command.
24984d9c625SLionel Sambuc  *
25084d9c625SLionel Sambuc  * PUBLIC: int v_change __P((SCR *, VICMD *));
25184d9c625SLionel Sambuc  */
25284d9c625SLionel Sambuc int
v_change(SCR * sp,VICMD * vp)25384d9c625SLionel Sambuc v_change(SCR *sp, VICMD *vp)
25484d9c625SLionel Sambuc {
25584d9c625SLionel Sambuc 	size_t blen, len;
25684d9c625SLionel Sambuc 	u_int32_t flags;
25784d9c625SLionel Sambuc 	int isempty, lmode, rval;
25884d9c625SLionel Sambuc 	CHAR_T *bp;
25984d9c625SLionel Sambuc 	CHAR_T *p;
26084d9c625SLionel Sambuc 
26184d9c625SLionel Sambuc 	/*
26284d9c625SLionel Sambuc 	 * 'c' can be combined with motion commands that set the resulting
26384d9c625SLionel Sambuc 	 * cursor position, i.e. "cG".  Clear the VM_RCM flags and make the
26484d9c625SLionel Sambuc 	 * resulting cursor position stick, inserting text has its own rules
26584d9c625SLionel Sambuc 	 * for cursor positioning.
26684d9c625SLionel Sambuc 	 */
26784d9c625SLionel Sambuc 	F_CLR(vp, VM_RCM_MASK);
26884d9c625SLionel Sambuc 	F_SET(vp, VM_RCM_SET);
26984d9c625SLionel Sambuc 
27084d9c625SLionel Sambuc 	/*
27184d9c625SLionel Sambuc 	 * Find out if the file is empty, it's easier to handle it as a
27284d9c625SLionel Sambuc 	 * special case.
27384d9c625SLionel Sambuc 	 */
27484d9c625SLionel Sambuc 	if (vp->m_start.lno == vp->m_stop.lno &&
27584d9c625SLionel Sambuc 	    db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
27684d9c625SLionel Sambuc 		if (!isempty)
27784d9c625SLionel Sambuc 			return (1);
27884d9c625SLionel Sambuc 		return (v_ia(sp, vp));
27984d9c625SLionel Sambuc 	}
28084d9c625SLionel Sambuc 
28184d9c625SLionel Sambuc 	flags = set_txt_std(sp, vp, 0);
28284d9c625SLionel Sambuc 	sp->showmode = SM_CHANGE;
28384d9c625SLionel Sambuc 
28484d9c625SLionel Sambuc 	/*
28584d9c625SLionel Sambuc 	 * Move the cursor to the start of the change.  Note, if autoindent
28684d9c625SLionel Sambuc 	 * is turned on, the cc command in line mode changes from the first
28784d9c625SLionel Sambuc 	 * *non-blank* character of the line, not the first character.  And,
28884d9c625SLionel Sambuc 	 * to make it just a bit more exciting, the initial space is handled
28984d9c625SLionel Sambuc 	 * as auto-indent characters.
29084d9c625SLionel Sambuc 	 */
29184d9c625SLionel Sambuc 	lmode = F_ISSET(vp, VM_LMODE) ? CUT_LINEMODE : 0;
29284d9c625SLionel Sambuc 	if (lmode) {
29384d9c625SLionel Sambuc 		vp->m_start.cno = 0;
29484d9c625SLionel Sambuc 		if (O_ISSET(sp, O_AUTOINDENT)) {
29584d9c625SLionel Sambuc 			if (nonblank(sp, vp->m_start.lno, &vp->m_start.cno))
29684d9c625SLionel Sambuc 				return (1);
29784d9c625SLionel Sambuc 			LF_SET(TXT_AICHARS);
29884d9c625SLionel Sambuc 		}
29984d9c625SLionel Sambuc 	}
30084d9c625SLionel Sambuc 	sp->lno = vp->m_start.lno;
30184d9c625SLionel Sambuc 	sp->cno = vp->m_start.cno;
30284d9c625SLionel Sambuc 
30384d9c625SLionel Sambuc 	LOG_CORRECT;
30484d9c625SLionel Sambuc 
30584d9c625SLionel Sambuc 	/*
30684d9c625SLionel Sambuc 	 * If not in line mode and changing within a single line, copy the
30784d9c625SLionel Sambuc 	 * text and overwrite it.
30884d9c625SLionel Sambuc 	 */
30984d9c625SLionel Sambuc 	if (!lmode && vp->m_start.lno == vp->m_stop.lno) {
31084d9c625SLionel Sambuc 		/*
31184d9c625SLionel Sambuc 		 * !!!
31284d9c625SLionel Sambuc 		 * Historic practice, c did not cut into the numeric buffers,
31384d9c625SLionel Sambuc 		 * only the unnamed one.
31484d9c625SLionel Sambuc 		 */
31584d9c625SLionel Sambuc 		if (cut(sp,
31684d9c625SLionel Sambuc 		    F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
31784d9c625SLionel Sambuc 		    &vp->m_start, &vp->m_stop, lmode))
31884d9c625SLionel Sambuc 			return (1);
31984d9c625SLionel Sambuc 		if (len == 0)
32084d9c625SLionel Sambuc 			LF_SET(TXT_APPENDEOL);
32184d9c625SLionel Sambuc 		LF_SET(TXT_EMARK | TXT_OVERWRITE);
32284d9c625SLionel Sambuc 		return (v_txt(sp, vp, &vp->m_stop, p, len,
32384d9c625SLionel Sambuc 		    0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags));
32484d9c625SLionel Sambuc 	}
32584d9c625SLionel Sambuc 
32684d9c625SLionel Sambuc 	/*
32784d9c625SLionel Sambuc 	 * It's trickier if in line mode or changing over multiple lines.  If
32884d9c625SLionel Sambuc 	 * we're in line mode delete all of the lines and insert a replacement
32984d9c625SLionel Sambuc 	 * line which the user edits.  If there was leading whitespace in the
33084d9c625SLionel Sambuc 	 * first line being changed, we copy it and use it as the replacement.
33184d9c625SLionel Sambuc 	 * If we're not in line mode, we delete the text and start inserting.
33284d9c625SLionel Sambuc 	 *
33384d9c625SLionel Sambuc 	 * !!!
33484d9c625SLionel Sambuc 	 * Copy the text.  Historic practice, c did not cut into the numeric
33584d9c625SLionel Sambuc 	 * buffers, only the unnamed one.
33684d9c625SLionel Sambuc 	 */
33784d9c625SLionel Sambuc 	if (cut(sp,
33884d9c625SLionel Sambuc 	    F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
33984d9c625SLionel Sambuc 	    &vp->m_start, &vp->m_stop, lmode))
34084d9c625SLionel Sambuc 		return (1);
34184d9c625SLionel Sambuc 
34284d9c625SLionel Sambuc 	/* If replacing entire lines and there's leading text. */
34384d9c625SLionel Sambuc 	if (lmode && vp->m_start.cno) {
34484d9c625SLionel Sambuc 		/*
34584d9c625SLionel Sambuc 		 * Get a copy of the first line changed, and copy out the
34684d9c625SLionel Sambuc 		 * leading text.
34784d9c625SLionel Sambuc 		 */
34884d9c625SLionel Sambuc 		if (db_get(sp, vp->m_start.lno, DBG_FATAL, &p, &len))
34984d9c625SLionel Sambuc 			return (1);
35084d9c625SLionel Sambuc 		GET_SPACE_RETW(sp, bp, blen, vp->m_start.cno);
35184d9c625SLionel Sambuc 		MEMMOVEW(bp, p, vp->m_start.cno);
35284d9c625SLionel Sambuc 	} else
35384d9c625SLionel Sambuc 		bp = NULL;
35484d9c625SLionel Sambuc 
35584d9c625SLionel Sambuc 	/* Delete the text. */
35684d9c625SLionel Sambuc 	if (del(sp, &vp->m_start, &vp->m_stop, lmode))
35784d9c625SLionel Sambuc 		return (1);
35884d9c625SLionel Sambuc 
35984d9c625SLionel Sambuc 	/* If replacing entire lines, insert a replacement line. */
36084d9c625SLionel Sambuc 	if (lmode) {
36184d9c625SLionel Sambuc 		if (db_insert(sp, vp->m_start.lno, bp, vp->m_start.cno))
36284d9c625SLionel Sambuc 			return (1);
36384d9c625SLionel Sambuc 		sp->lno = vp->m_start.lno;
36484d9c625SLionel Sambuc 		len = sp->cno = vp->m_start.cno;
36584d9c625SLionel Sambuc 	}
36684d9c625SLionel Sambuc 
36784d9c625SLionel Sambuc 	/* Get the line we're editing. */
36884d9c625SLionel Sambuc 	if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
36984d9c625SLionel Sambuc 		if (!isempty)
37084d9c625SLionel Sambuc 			return (1);
37184d9c625SLionel Sambuc 		len = 0;
37284d9c625SLionel Sambuc 	}
37384d9c625SLionel Sambuc 
37484d9c625SLionel Sambuc 	/* Check to see if we're appending to the line. */
37584d9c625SLionel Sambuc 	if (vp->m_start.cno >= len)
37684d9c625SLionel Sambuc 		LF_SET(TXT_APPENDEOL);
37784d9c625SLionel Sambuc 
37884d9c625SLionel Sambuc 	rval = v_txt(sp, vp, NULL, p, len,
37984d9c625SLionel Sambuc 	    0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags);
38084d9c625SLionel Sambuc 
38184d9c625SLionel Sambuc 	if (bp != NULL)
38284d9c625SLionel Sambuc 		FREE_SPACEW(sp, bp, blen);
38384d9c625SLionel Sambuc 	return (rval);
38484d9c625SLionel Sambuc }
38584d9c625SLionel Sambuc 
38684d9c625SLionel Sambuc /*
38784d9c625SLionel Sambuc  * v_Replace -- [count]R
38884d9c625SLionel Sambuc  *	Overwrite multiple characters.
38984d9c625SLionel Sambuc  *
39084d9c625SLionel Sambuc  * PUBLIC: int v_Replace __P((SCR *, VICMD *));
39184d9c625SLionel Sambuc  */
39284d9c625SLionel Sambuc int
v_Replace(SCR * sp,VICMD * vp)39384d9c625SLionel Sambuc v_Replace(SCR *sp, VICMD *vp)
39484d9c625SLionel Sambuc {
39584d9c625SLionel Sambuc 	size_t len;
39684d9c625SLionel Sambuc 	u_int32_t flags;
39784d9c625SLionel Sambuc 	int isempty;
39884d9c625SLionel Sambuc 	CHAR_T *p;
39984d9c625SLionel Sambuc 
40084d9c625SLionel Sambuc 	flags = set_txt_std(sp, vp, 0);
40184d9c625SLionel Sambuc 	sp->showmode = SM_REPLACE;
40284d9c625SLionel Sambuc 
40384d9c625SLionel Sambuc 	if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
40484d9c625SLionel Sambuc 		if (!isempty)
40584d9c625SLionel Sambuc 			return (1);
40684d9c625SLionel Sambuc 		len = 0;
40784d9c625SLionel Sambuc 		LF_SET(TXT_APPENDEOL);
40884d9c625SLionel Sambuc 	} else {
40984d9c625SLionel Sambuc 		if (len == 0)
41084d9c625SLionel Sambuc 			LF_SET(TXT_APPENDEOL);
41184d9c625SLionel Sambuc 		LF_SET(TXT_OVERWRITE | TXT_REPLACE);
41284d9c625SLionel Sambuc 	}
41384d9c625SLionel Sambuc 	vp->m_stop.lno = vp->m_start.lno;
41484d9c625SLionel Sambuc 	vp->m_stop.cno = len ? len - 1 : 0;
41584d9c625SLionel Sambuc 
41684d9c625SLionel Sambuc 	return (v_txt(sp, vp, &vp->m_stop, p, len,
41784d9c625SLionel Sambuc 	    0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags));
41884d9c625SLionel Sambuc }
41984d9c625SLionel Sambuc 
42084d9c625SLionel Sambuc /*
42184d9c625SLionel Sambuc  * v_subst -- [buffer][count]s
42284d9c625SLionel Sambuc  *	Substitute characters.
42384d9c625SLionel Sambuc  *
42484d9c625SLionel Sambuc  * PUBLIC: int v_subst __P((SCR *, VICMD *));
42584d9c625SLionel Sambuc  */
42684d9c625SLionel Sambuc int
v_subst(SCR * sp,VICMD * vp)42784d9c625SLionel Sambuc v_subst(SCR *sp, VICMD *vp)
42884d9c625SLionel Sambuc {
42984d9c625SLionel Sambuc 	size_t len;
43084d9c625SLionel Sambuc 	u_int32_t flags;
43184d9c625SLionel Sambuc 	int isempty;
43284d9c625SLionel Sambuc 	CHAR_T *p;
43384d9c625SLionel Sambuc 
43484d9c625SLionel Sambuc 	flags = set_txt_std(sp, vp, 0);
43584d9c625SLionel Sambuc 	sp->showmode = SM_CHANGE;
43684d9c625SLionel Sambuc 
43784d9c625SLionel Sambuc 	if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
43884d9c625SLionel Sambuc 		if (!isempty)
43984d9c625SLionel Sambuc 			return (1);
44084d9c625SLionel Sambuc 		len = 0;
44184d9c625SLionel Sambuc 		LF_SET(TXT_APPENDEOL);
44284d9c625SLionel Sambuc 	} else {
44384d9c625SLionel Sambuc 		if (len == 0)
44484d9c625SLionel Sambuc 			LF_SET(TXT_APPENDEOL);
44584d9c625SLionel Sambuc 		LF_SET(TXT_EMARK | TXT_OVERWRITE);
44684d9c625SLionel Sambuc 	}
44784d9c625SLionel Sambuc 
44884d9c625SLionel Sambuc 	vp->m_stop.lno = vp->m_start.lno;
44984d9c625SLionel Sambuc 	vp->m_stop.cno =
45084d9c625SLionel Sambuc 	    vp->m_start.cno + (F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0);
45184d9c625SLionel Sambuc 	if (vp->m_stop.cno > len - 1)
45284d9c625SLionel Sambuc 		vp->m_stop.cno = len - 1;
45384d9c625SLionel Sambuc 
45484d9c625SLionel Sambuc 	if (p != NULL && cut(sp,
45584d9c625SLionel Sambuc 	    F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
45684d9c625SLionel Sambuc 	    &vp->m_start, &vp->m_stop, 0))
45784d9c625SLionel Sambuc 		return (1);
45884d9c625SLionel Sambuc 
45984d9c625SLionel Sambuc 	return (v_txt(sp, vp, &vp->m_stop, p, len, 0, OOBLNO, 1, flags));
46084d9c625SLionel Sambuc }
46184d9c625SLionel Sambuc 
46284d9c625SLionel Sambuc /*
46384d9c625SLionel Sambuc  * set_txt_std --
46484d9c625SLionel Sambuc  *	Initialize text processing flags.
46584d9c625SLionel Sambuc  */
46684d9c625SLionel Sambuc static u_int32_t
set_txt_std(SCR * sp,VICMD * vp,u_int32_t flags)46784d9c625SLionel Sambuc set_txt_std(SCR *sp, VICMD *vp, u_int32_t flags)
46884d9c625SLionel Sambuc {
46984d9c625SLionel Sambuc 	LF_SET(TXT_CNTRLT |
47084d9c625SLionel Sambuc 	    TXT_ESCAPE | TXT_MAPINPUT | TXT_RECORD | TXT_RESOLVE);
47184d9c625SLionel Sambuc 
47284d9c625SLionel Sambuc 	if (F_ISSET(vp, VC_ISDOT))
47384d9c625SLionel Sambuc 		LF_SET(TXT_REPLAY);
47484d9c625SLionel Sambuc 
47584d9c625SLionel Sambuc 	if (O_ISSET(sp, O_ALTWERASE))
47684d9c625SLionel Sambuc 		LF_SET(TXT_ALTWERASE);
47784d9c625SLionel Sambuc 	if (O_ISSET(sp, O_AUTOINDENT))
47884d9c625SLionel Sambuc 		LF_SET(TXT_AUTOINDENT);
47984d9c625SLionel Sambuc 	if (O_ISSET(sp, O_BEAUTIFY))
48084d9c625SLionel Sambuc 		LF_SET(TXT_BEAUTIFY);
48184d9c625SLionel Sambuc 	if (O_ISSET(sp, O_SHOWMATCH))
48284d9c625SLionel Sambuc 		LF_SET(TXT_SHOWMATCH);
48384d9c625SLionel Sambuc 	if (F_ISSET(sp, SC_SCRIPT))
48484d9c625SLionel Sambuc 		LF_SET(TXT_CR);
48584d9c625SLionel Sambuc 	if (O_ISSET(sp, O_TTYWERASE))
48684d9c625SLionel Sambuc 		LF_SET(TXT_TTYWERASE);
48784d9c625SLionel Sambuc 
48884d9c625SLionel Sambuc 	/*
48984d9c625SLionel Sambuc 	 * !!!
49084d9c625SLionel Sambuc 	 * Mapped keys were sometimes unaffected by the wrapmargin option
49184d9c625SLionel Sambuc 	 * in the historic 4BSD vi.  Consider the following commands, where
49284d9c625SLionel Sambuc 	 * each is executed on an empty line, in an 80 column screen, with
49384d9c625SLionel Sambuc 	 * the wrapmargin value set to 60.
49484d9c625SLionel Sambuc 	 *
49584d9c625SLionel Sambuc 	 *	aABC DEF <ESC>....
49684d9c625SLionel Sambuc 	 *	:map K aABC DEF ^V<ESC><CR>KKKKK
49784d9c625SLionel Sambuc 	 *	:map K 5aABC DEF ^V<ESC><CR>K
49884d9c625SLionel Sambuc 	 *
49984d9c625SLionel Sambuc 	 * The first and second commands are affected by wrapmargin.  The
50084d9c625SLionel Sambuc 	 * third is not.  (If the inserted text is itself longer than the
50184d9c625SLionel Sambuc 	 * wrapmargin value, i.e. if the "ABC DEF " string is replaced by
50284d9c625SLionel Sambuc 	 * something that's longer than 60 columns from the beginning of
50384d9c625SLionel Sambuc 	 * the line, the first two commands behave as before, but the third
50484d9c625SLionel Sambuc 	 * command gets fairly strange.)  The problem is that people wrote
50584d9c625SLionel Sambuc 	 * macros that depended on the third command NOT being affected by
50684d9c625SLionel Sambuc 	 * wrapmargin, as in this gem which centers lines:
50784d9c625SLionel Sambuc 	 *
50884d9c625SLionel Sambuc 	 *	map #c $mq81a ^V^[81^V^V|D`qld0:s/  / /g^V^M$p
50984d9c625SLionel Sambuc 	 *
51084d9c625SLionel Sambuc 	 * For compatibility reasons, we try and make it all work here.  I
51184d9c625SLionel Sambuc 	 * offer no hope that this is right, but it's probably pretty close.
51284d9c625SLionel Sambuc 	 *
51384d9c625SLionel Sambuc 	 * XXX
51484d9c625SLionel Sambuc 	 * Once I work my courage up, this is all gonna go away.  It's too
51584d9c625SLionel Sambuc 	 * evil to survive.
51684d9c625SLionel Sambuc 	 */
51784d9c625SLionel Sambuc 	if ((O_ISSET(sp, O_WRAPLEN) || O_ISSET(sp, O_WRAPMARGIN)) &&
51884d9c625SLionel Sambuc 	    (!MAPPED_KEYS_WAITING(sp) || !F_ISSET(vp, VC_C1SET)))
51984d9c625SLionel Sambuc 		LF_SET(TXT_WRAPMARGIN);
52084d9c625SLionel Sambuc 	return (flags);
52184d9c625SLionel Sambuc }
522