memmove(bp, s, llen);
memcpy(bp, s, llen);
s(sp, cmdp, s, re, flags)	SCR *sp;	EXCMD *cmdp;	char *s;	regex_t *re;	u_int flags;{	EVENT ev;	MARK from, to;	TEXTH tiq;	recno_t elno, lno, slno;	regmatch_t match[10];	size_t blen, cnt, last, lbclen, lblen, len, llen;	size_t offset, saved_offset, scno;	int cflag, lflag, nflag, pflag, rflag;	int didsub, do_eol_match, eflags, empty_ok, eval;	int linechanged, matched, quit, rval;	char *bp, *lb;	NEEDFILE(sp, cmdp);	slno = sp->lno;	scno = sp->cno;	/*	 * !!!	 * Historically, the 'g' and 'c' suffices were always toggled as flags,	 * so ":s/A/B/" was the same as ":s/A/B/ccgg".  If O_EDCOMPATIBLE was	 * not set, they were initialized to 0 for all substitute commands.  If	 * O_EDCOMPATIBLE was set, they were initialized to 0 only if the user	 * specified substitute/replacement patterns (see ex_s()).	 */	if (!O_ISSET(sp, O_EDCOMPATIBLE))		sp->c_suffix = sp->g_suffix = 0;	/*	 * Historic vi permitted the '#', 'l' and 'p' options in vi mode, but	 * it only displayed the last change.  I'd disallow them, but they are	 * useful in combination with the [v]global commands.  In the current	 * model the problem is combining them with the 'c' flag -- the screen	 * would have to flip back and forth between the confirm screen and the	 * ex print screen, which would be pretty awful.  We do display all	 * changes, though, for what that's worth.	 *	 * !!!	 * Historic vi was fairly strict about the order of "options", the	 * count, and "flags".  I'm somewhat fuzzy on the difference between	 * options and flags, anyway, so this is a simpler approach, and we	 * just take it them in whatever order the user gives them.  (The ex	 * usage statement doesn't reflect this.)	 */	cflag = lflag = nflag = pflag = rflag = 0;	if (s == NULL)		goto noargs;	for (lno = OOBLNO; *s != '\0'; ++s)		switch (*s) {		case ' ':		case '\t':			continue;		case '+':			++cmdp->flagoff;			break;		case '-':			--cmdp->flagoff;			break;		case '0': case '1': case '2': case '3': case '4':		case '5': case '6': case '7': case '8': case '9':			if (lno != OOBLNO)				goto usage;			errno = 0;			lno = strtoul(s, &s, 10);			if (*s == '\0')		/* Loop increment correction. */				--s;			if (errno == ERANGE) {				if (lno == LONG_MAX)					msgq(sp, M_ERR, "153|Count overflow");				else if (lno == LONG_MIN)					msgq(sp, M_ERR, "154|Count underflow");				else					msgq(sp, M_SYSERR, NULL);				return (1);			}			/*			 * In historic vi, the count was inclusive from the			 * second address.			 */			cmdp->addr1.lno = cmdp->addr2.lno;			cmdp->addr2.lno += lno - 1;			if (!db_exist(sp, cmdp->addr2.lno) &&			    db_last(sp, &cmdp->addr2.lno))				return (1);			break;		case '#':			nflag = 1;			break;		case 'c':			sp->c_suffix = !sp->c_suffix;			/* Ex text structure initialization. */			if (F_ISSET(sp, SC_EX)) {				memset(&tiq, 0, sizeof(TEXTH));				CIRCLEQ_INIT(&tiq);			}			break;		case 'g':			sp->g_suffix = !sp->g_suffix;			break;		case 'l':			lflag = 1;			break;		case 'p':			pflag = 1;			break;		case 'r':			if (LF_ISSET(SUB_FIRST)) {				msgq(sp, M_ERR,		    "155|Regular expression specified; r flag meaningless");				return (1);			}			if (!F_ISSET(sp, SC_RE_SEARCH)) {				ex_emsg(sp, NULL, EXM_NOPREVRE);				return (1);			}			rflag = 1;			re = &sp->re_c;			break;		default:			goto usage;		}	if (*s != '\0' || !rflag && LF_ISSET(SUB_MUSTSETR)) {usage:		ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);		return (1);	}noargs:	if (F_ISSET(sp, SC_VI) && sp->c_suffix && (lflag || nflag || pflag)) {		msgq(sp, M_ERR,"156|The #, l and p flags may not be combined with the c flag in vi mode");		return (1);	}	/*	 * bp:		if interactive, line cache	 * blen:	if interactive, line cache length	 * lb:		build buffer pointer.	 * lbclen:	current length of built buffer.	 * lblen;	length of build buffer.	 */	bp = lb = NULL;	blen = lbclen = lblen = 0;	/* For each line... */	for (matched = quit = 0, lno = cmdp->addr1.lno,	    elno = cmdp->addr2.lno; !quit && lno <= elno; ++lno) {		/* Someone's unhappy, time to stop. */		if (INTERRUPTED(sp))			break;		/* Get the line. */		if (db_get(sp, lno, DBG_FATAL, &s, &llen))			goto err;		/*		 * Make a local copy if doing confirmation -- when calling		 * the confirm routine we're likely to lose the cached copy.		 */		if (sp->c_suffix) {			if (bp == NULL) {				GET_SPACE_RET(sp, bp, blen, llen);			} else				ADD_SPACE_RET(sp, bp, blen, llen);			memmove(bp, s, llen);			s = bp;		}		/* Start searching from the beginning. */		offset = 0;		len = llen;		/* Reset the build buffer offset. */		lbclen = 0;		/* Reset empty match flag. */		empty_ok = 1;		/*		 * We don't want to have to do a setline if the line didn't		 * change -- keep track of whether or not this line changed.		 * If doing confirmations, don't want to keep setting the		 * line if change is refused -- keep track of substitutions.		 */		didsub = linechanged = 0;		/* New line, do an EOL match. */		do_eol_match = 1;		/* It's not nul terminated, but we pretend it is. */		eflags = REG_STARTEND;		/*		 * The search area is from s + offset to the EOL.		 *		 * Generally, match[0].rm_so is the offset of the start		 * of the match from the start of the search, and offset		 * is the offset of the start of the last search.		 */nextmatch:	match[0].rm_so = 0;		match[0].rm_eo = len;		/* Get the next match. */		eval = regexec(re, (char *)s + offset, 10, match, eflags);		/*		 * There wasn't a match or if there was an error, deal with		 * it.  If there was a previous match in this line, resolve		 * the changes into the database.  Otherwise, just move on.		 */		if (eval == REG_NOMATCH)			goto endmatch;		if (eval != 0) {			re_error(sp, eval, re);			goto err;		}		matched = 1;		/* Only the first search can match an anchored expression. */		eflags |= REG_NOTBOL;		/*		 * !!!		 * It's possible to match 0-length strings -- for example, the		 * command s;a*;X;, when matched against the string "aabb" will		 * result in "XbXbX", i.e. the matches are "aa", the space		 * between the b's and the space between the b's and the end of		 * the string.  There is a similar space between the beginning		 * of the string and the a's.  The rule that we use (because vi		 * historically used it) is that any 0-length match, occurring		 * immediately after a match, is ignored.  Otherwise, the above		 * example would have resulted in "XXbXbX".  Another example is		 * incorrectly using " *" to replace groups of spaces with one		 * space.		 *		 * The way we do this is that if we just had a successful match,		 * the starting offset does not skip characters, and the match		 * is empty, ignore the match and move forward.  If there's no		 * more characters in the string, we were attempting to match		 * after the last character, so quit.		 */		if (!empty_ok && match[0].rm_so == 0 && match[0].rm_eo == 0) {			empty_ok = 1;			if (len == 0)				goto endmatch;			BUILD(sp, s + offset, 1)			++offset;			--len;			goto nextmatch;		}		/* Confirm change. */		if (sp->c_suffix) {			/*			 * Set the cursor position for confirmation.  Note,			 * if we matched on a '$', the cursor may be past			 * the end of line.			 */			from.lno = to.lno = lno;			from.cno = match[0].rm_so + offset;			to.cno = match[0].rm_eo + offset;			/*			 * Both ex and vi have to correct for a change before			 * the first character in the line.			 */			if (llen == 0)				from.cno = to.cno = 0;			if (F_ISSET(sp, SC_VI)) {				/*				 * Only vi has to correct for a change after				 * the last character in the line.				 *				 * XXX				 * It would be nice to change the vi code so				 * that we could display a cursor past EOL.				 */				if (to.cno >= llen)					to.cno = llen - 1;				if (from.cno >= llen)					from.cno = llen - 1;				sp->lno = from.lno;				sp->cno = from.cno;				if (vs_refresh(sp, 1))					goto err;				vs_update(sp, msg_cat(sp,				    "169|Confirm change? [n]", NULL), NULL);				if (v_event_get(sp, &ev, 0, 0))					goto err;				switch (ev.e_event) {				case E_CHARACTER:					break;				case E_EOF:				case E_ERR:				case E_INTERRUPT:					goto lquit;				default:					v_event_err(sp, &ev);					goto lquit;				}			} else {				if (ex_print(sp, cmdp, &from, &to, 0) ||				    ex_scprint(sp, &from, &to))					goto lquit;				if (ex_txt(sp, &tiq, 0, TXT_CR))					goto err;				ev.e_c = tiq.cqh_first->lb[0];			}			switch (ev.e_c) {			case CH_YES:				break;			default:			case CH_NO:				didsub = 0;				BUILD(sp, s +offset, match[0].rm_eo);				goto skip;			case CH_QUIT:				/* Set the quit/interrupted flags. */lquit:				quit = 1;				F_SET(sp->gp, G_INTERRUPTED);				/*				 * Resolve any changes, then return to (and				 * exit from) the main loop.				 */				goto endmatch;			}		}		/*		 * Set the cursor to the last position changed, converting		 * from 1-based to 0-based.		 */		sp->lno = lno;		sp->cno = match[0].rm_so;		/* Copy the bytes before the match into the build buffer. */		BUILD(sp, s + offset, match[0].rm_so);		/* Substitute the matching bytes. */		didsub = 1;		if (re_sub(sp, s + offset, &lb, &lbclen, &lblen, match))			goto err;		/* Set the change flag so we know this line was modified. */		linechanged = 1;		/* Move past the matched bytes. */skip:		offset += match[0].rm_eo;		len -= match[0].rm_eo;		/* A match cannot be followed by an empty pattern. */		empty_ok = 0;		/*		 * If doing a global change with confirmation, we have to		 * update the screen.  The basic idea is to store the line		 * so the screen update routines can find it, and restart.		 */		if (didsub && sp->c_suffix && sp->g_suffix) {			/*			 * The new search offset will be the end of the			 * modified line.			 */			saved_offset = lbclen;			/* Copy the rest of the line. */			if (len)				BUILD(sp, s + offset, len)			/* Set the new offset. */			offset = saved_offset;			/* Store inserted lines, adjusting the build buffer. */			last = 0;			if (sp->newl_cnt) {				for (cnt = 0;				    cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) {					if (db_insert(sp, lno,					    lb + last, sp->newl[cnt] - last))						goto err;					last = sp->newl[cnt] + 1;					++sp->rptlines[L_ADDED];				}				lbclen -= last;				offset -= last;				sp->newl_cnt = 0;			}			/* Store and retrieve the line. */			if (db_set(sp, lno, lb + last, lbclen))				goto err;			if (db_get(sp, lno, DBG_FATAL, &s, &llen))				goto err;			ADD_SPACE_RET(sp, bp, blen, llen)			memmove(bp, s, llen);			s = bp;			len = llen - offset;			/* Restart the build. */			lbclen = 0;			BUILD(sp, s, offset);			/*			 * If we haven't already done the after-the-string			 * match, do one.  Set REG_NOTEOL so the '$' pattern			 * only matches once.			 */			if (!do_eol_match)				goto endmatch;			if (offset == len) {				do_eol_match = 0;				eflags |= REG_NOTEOL;			}			goto nextmatch;		}		/*		 * If it's a global:		 *		 * If at the end of the string, do a test for the after		 * the string match.  Set REG_NOTEOL so the '$' pattern		 * only matches once.		 */		if (sp->g_suffix && do_eol_match) {			if (len == 0) {				do_eol_match = 0;				eflags |= REG_NOTEOL;			}			goto nextmatch;		}endmatch:	if (!linechanged)			continue;		/* Copy any remaining bytes into the build buffer. */		if (len)			BUILD(sp, s + offset, len)		/* Store inserted lines, adjusting the build buffer. */		last = 0;		if (sp->newl_cnt) {			for (cnt = 0;			    cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) {				if (db_insert(sp,				    lno, lb + last, sp->newl[cnt] - last))					goto err;				last = sp->newl[cnt] + 1;				++sp->rptlines[L_ADDED];			}			lbclen -= last;			sp->newl_cnt = 0;		}		/* Store the changed line. */		if (db_set(sp, lno, lb + last, lbclen))			goto err;		/* Update changed line counter. */		if (sp->rptlchange != lno) {			sp->rptlchange = lno;			++sp->rptlines[L_CHANGED];		}		/*		 * !!!		 * Display as necessary.  Historic practice is to only		 * display the last line of a line split into multiple		 * lines.		 */		if (lflag || nflag || pflag) {			from.lno = to.lno = lno;			from.cno = to.cno = 0;			if (lflag)				(void)ex_print(sp, cmdp, &from, &to, E_C_LIST);			if (nflag)				(void)ex_print(sp, cmdp, &from, &to, E_C_HASH);			if (pflag)				(void)ex_print(sp, cmdp, &from, &to, E_C_PRINT);		}	}	/*	 * !!!	 * Historically, vi attempted to leave the cursor at the same place if	 * the substitution was done at the current cursor position.  Otherwise	 * it moved it to the first non-blank of the last line changed.  There	 * were some problems: for example, :s/$/foo/ with the cursor on the	 * last character of the line left the cursor on the last character, or	 * the & command with multiple occurrences of the matching string in the	 * line usually left the cursor in a fairly random position.	 *	 * We try to do the same thing, with the exception that if the user is	 * doing substitution with confirmation, we move to the last line about	 * which the user was consulted, as opposed to the last line that they	 * actually changed.  This prevents a screen flash if the user doesn't	 * change many of the possible lines.	 */	if (!sp->c_suffix && (sp->lno != slno || sp->cno != scno)) {		sp->cno = 0;		(void)nonblank(sp, sp->lno, &sp->cno);	}	/*	 * If not in a global command, and nothing matched, say so.	 * Else, if none of the lines displayed, put something up.	 */	rval = 0;	if (!matched) {		if (!F_ISSET(sp, SC_EX_GLOBAL)) {			msgq(sp, M_ERR, "157|No match found");			goto err;		}	} else if (!lflag && !nflag && !pflag)		F_SET(cmdp, E_AUTOPRINT);	if (0) {err:		rval = 1;	}	if (bp != NULL)		FREE_SPACE(sp, bp, blen);	if (lb != NULL)		free(lb);	return (rval);}