xref: /netbsd/external/bsd/nvi/dist/ex/ex_subst.c (revision cc73507a)
1*cc73507aSchristos /*	$NetBSD: ex_subst.c,v 1.4 2014/01/26 21:43:45 christos Exp $ */
23a571abcSchristos /*-
33a571abcSchristos  * Copyright (c) 1992, 1993, 1994
43a571abcSchristos  *	The Regents of the University of California.  All rights reserved.
53a571abcSchristos  * Copyright (c) 1992, 1993, 1994, 1995, 1996
63a571abcSchristos  *	Keith Bostic.  All rights reserved.
73a571abcSchristos  *
83a571abcSchristos  * See the LICENSE file for redistribution information.
93a571abcSchristos  */
103a571abcSchristos 
113a571abcSchristos #include "config.h"
123a571abcSchristos 
13*cc73507aSchristos #include <sys/cdefs.h>
14*cc73507aSchristos #if 0
153a571abcSchristos #ifndef lint
163a571abcSchristos static const char sccsid[] = "Id: ex_subst.c,v 10.50 2002/02/09 21:18:23 skimo Exp  (Berkeley) Date: 2002/02/09 21:18:23 ";
173a571abcSchristos #endif /* not lint */
18*cc73507aSchristos #else
19*cc73507aSchristos __RCSID("$NetBSD: ex_subst.c,v 1.4 2014/01/26 21:43:45 christos Exp $");
20*cc73507aSchristos #endif
213a571abcSchristos 
223a571abcSchristos #include <sys/types.h>
233a571abcSchristos #include <sys/queue.h>
243a571abcSchristos #include <sys/time.h>
253a571abcSchristos 
263a571abcSchristos #include <bitstring.h>
273a571abcSchristos #include <ctype.h>
283a571abcSchristos #include <errno.h>
293a571abcSchristos #include <limits.h>
303a571abcSchristos #include <stdio.h>
313a571abcSchristos #include <stdlib.h>
323a571abcSchristos #include <string.h>
333a571abcSchristos #include <unistd.h>
343a571abcSchristos 
353a571abcSchristos #include "../common/common.h"
363a571abcSchristos #include "../vi/vi.h"
373a571abcSchristos 
383a571abcSchristos #define	SUB_FIRST	0x01		/* The 'r' flag isn't reasonable. */
393a571abcSchristos #define	SUB_MUSTSETR	0x02		/* The 'r' flag is required. */
403a571abcSchristos 
413a571abcSchristos static int re_conv __P((SCR *, CHAR_T **, size_t *, int *));
423a571abcSchristos static int re_cscope_conv __P((SCR *, CHAR_T **, size_t *, int *));
433a571abcSchristos static int re_sub __P((SCR *,
443a571abcSchristos 		CHAR_T *, CHAR_T **, size_t *, size_t *, regmatch_t [10]));
453a571abcSchristos static int re_tag_conv __P((SCR *, CHAR_T **, size_t *, int *));
463a571abcSchristos static int s __P((SCR *, EXCMD *, CHAR_T *, regex_t *, u_int));
473a571abcSchristos 
483a571abcSchristos /*
493a571abcSchristos  * ex_s --
503a571abcSchristos  *	[line [,line]] s[ubstitute] [[/;]pat[/;]/repl[/;] [cgr] [count] [#lp]]
513a571abcSchristos  *
523a571abcSchristos  *	Substitute on lines matching a pattern.
533a571abcSchristos  *
543a571abcSchristos  * PUBLIC: int ex_s __P((SCR *, EXCMD *));
553a571abcSchristos  */
563a571abcSchristos int
ex_s(SCR * sp,EXCMD * cmdp)573a571abcSchristos ex_s(SCR *sp, EXCMD *cmdp)
583a571abcSchristos {
593a571abcSchristos 	regex_t *re;
603a571abcSchristos 	size_t blen, len;
613a571abcSchristos 	u_int flags;
6208d478e3Schristos 	ARG_CHAR_T delim;
633a571abcSchristos 	CHAR_T *bp, *p, *ptrn, *rep, *t;
643a571abcSchristos 
653a571abcSchristos 	/*
663a571abcSchristos 	 * Skip leading white space.
673a571abcSchristos 	 *
683a571abcSchristos 	 * !!!
693a571abcSchristos 	 * Historic vi allowed any non-alphanumeric to serve as the
703a571abcSchristos 	 * substitution command delimiter.
713a571abcSchristos 	 *
723a571abcSchristos 	 * !!!
733a571abcSchristos 	 * If the arguments are empty, it's the same as &, i.e. we
743a571abcSchristos 	 * repeat the last substitution.
753a571abcSchristos 	 */
763a571abcSchristos 	if (cmdp->argc == 0)
773a571abcSchristos 		goto subagain;
783a571abcSchristos 	for (p = cmdp->argv[0]->bp,
793a571abcSchristos 	    len = cmdp->argv[0]->len; len > 0; --len, ++p) {
8008d478e3Schristos 		if (!ISBLANK((UCHAR_T)*p))
813a571abcSchristos 			break;
823a571abcSchristos 	}
833a571abcSchristos 	if (len == 0)
843a571abcSchristos subagain:	return (ex_subagain(sp, cmdp));
853a571abcSchristos 
8608d478e3Schristos 	delim = (UCHAR_T)*p++;
8708d478e3Schristos 	if (ISALNUM(delim) || delim == '\\')
883a571abcSchristos 		return (s(sp, cmdp, p, &sp->subre_c, SUB_MUSTSETR));
893a571abcSchristos 
903a571abcSchristos 	/*
913a571abcSchristos 	 * !!!
923a571abcSchristos 	 * The full-blown substitute command reset the remembered
933a571abcSchristos 	 * state of the 'c' and 'g' suffices.
943a571abcSchristos 	 */
953a571abcSchristos 	sp->c_suffix = sp->g_suffix = 0;
963a571abcSchristos 
973a571abcSchristos 	/*
983a571abcSchristos 	 * Get the pattern string, toss escaping characters.
993a571abcSchristos 	 *
1003a571abcSchristos 	 * !!!
1013a571abcSchristos 	 * Historic vi accepted any of the following forms:
1023a571abcSchristos 	 *
1033a571abcSchristos 	 *	:s/abc/def/		change "abc" to "def"
1043a571abcSchristos 	 *	:s/abc/def		change "abc" to "def"
1053a571abcSchristos 	 *	:s/abc/			delete "abc"
1063a571abcSchristos 	 *	:s/abc			delete "abc"
1073a571abcSchristos 	 *
1083a571abcSchristos 	 * QUOTING NOTE:
1093a571abcSchristos 	 *
1103a571abcSchristos 	 * Only toss an escaping character if it escapes a delimiter.
1113a571abcSchristos 	 * This means that "s/A/\\\\f" replaces "A" with "\\f".  It
1123a571abcSchristos 	 * would be nice to be more regular, i.e. for each layer of
1133a571abcSchristos 	 * escaping a single escaping character is removed, but that's
1143a571abcSchristos 	 * not how the historic vi worked.
1153a571abcSchristos 	 */
1163a571abcSchristos 	for (ptrn = t = p;;) {
1173a571abcSchristos 		if (p[0] == '\0' || p[0] == delim) {
1183a571abcSchristos 			if (p[0] == delim)
1193a571abcSchristos 				++p;
1203a571abcSchristos 			/*
1213a571abcSchristos 			 * !!!
1223a571abcSchristos 			 * Nul terminate the pattern string -- it's passed
1233a571abcSchristos 			 * to regcomp which doesn't understand anything else.
1243a571abcSchristos 			 */
1253a571abcSchristos 			*t = '\0';
1263a571abcSchristos 			break;
1273a571abcSchristos 		}
12808d478e3Schristos 		if (p[0] == '\\') {
1293a571abcSchristos 			if (p[1] == delim)
1303a571abcSchristos 				++p;
1313a571abcSchristos 			else if (p[1] == '\\')
1323a571abcSchristos 				*t++ = *p++;
13308d478e3Schristos 		}
1343a571abcSchristos 		*t++ = *p++;
1353a571abcSchristos 	}
1363a571abcSchristos 
1373a571abcSchristos 	/*
1383a571abcSchristos 	 * If the pattern string is empty, use the last RE (not just the
1393a571abcSchristos 	 * last substitution RE).
1403a571abcSchristos 	 */
1413a571abcSchristos 	if (*ptrn == '\0') {
1423a571abcSchristos 		if (sp->re == NULL) {
1433a571abcSchristos 			ex_emsg(sp, NULL, EXM_NOPREVRE);
1443a571abcSchristos 			return (1);
1453a571abcSchristos 		}
1463a571abcSchristos 
1473a571abcSchristos 		/* Re-compile the RE if necessary. */
1483a571abcSchristos 		if (!F_ISSET(sp, SC_RE_SEARCH) &&
1493a571abcSchristos 		    re_compile(sp, sp->re, sp->re_len,
1503a571abcSchristos 		    NULL, NULL, &sp->re_c, SEARCH_CSEARCH | SEARCH_MSG))
1513a571abcSchristos 			return (1);
1523a571abcSchristos 		flags = 0;
1533a571abcSchristos 	} else {
1543a571abcSchristos 		/*
1553a571abcSchristos 		 * !!!
1563a571abcSchristos 		 * Compile the RE.  Historic practice is that substitutes set
1573a571abcSchristos 		 * the search direction as well as both substitute and search
1583a571abcSchristos 		 * RE's.  We compile the RE twice, as we don't want to bother
1593a571abcSchristos 		 * ref counting the pattern string and (opaque) structure.
1603a571abcSchristos 		 */
1613a571abcSchristos 		if (re_compile(sp, ptrn, t - ptrn, &sp->re,
1623a571abcSchristos 		    &sp->re_len, &sp->re_c, SEARCH_CSEARCH | SEARCH_MSG))
1633a571abcSchristos 			return (1);
1643a571abcSchristos 		if (re_compile(sp, ptrn, t - ptrn, &sp->subre,
1653a571abcSchristos 		    &sp->subre_len, &sp->subre_c, SEARCH_CSUBST | SEARCH_MSG))
1663a571abcSchristos 			return (1);
1673a571abcSchristos 
1683a571abcSchristos 		flags = SUB_FIRST;
1693a571abcSchristos 		sp->searchdir = FORWARD;
1703a571abcSchristos 	}
1713a571abcSchristos 	re = &sp->re_c;
1723a571abcSchristos 
1733a571abcSchristos 	/*
1743a571abcSchristos 	 * Get the replacement string.
1753a571abcSchristos 	 *
1763a571abcSchristos 	 * The special character & (\& if O_MAGIC not set) matches the
1773a571abcSchristos 	 * entire RE.  No handling of & is required here, it's done by
1783a571abcSchristos 	 * re_sub().
1793a571abcSchristos 	 *
1803a571abcSchristos 	 * The special character ~ (\~ if O_MAGIC not set) inserts the
1813a571abcSchristos 	 * previous replacement string into this replacement string.
1823a571abcSchristos 	 * Count ~'s to figure out how much space we need.  We could
1833a571abcSchristos 	 * special case nonexistent last patterns or whether or not
1843a571abcSchristos 	 * O_MAGIC is set, but it's probably not worth the effort.
1853a571abcSchristos 	 *
1863a571abcSchristos 	 * QUOTING NOTE:
1873a571abcSchristos 	 *
1883a571abcSchristos 	 * Only toss an escaping character if it escapes a delimiter or
1893a571abcSchristos 	 * if O_MAGIC is set and it escapes a tilde.
1903a571abcSchristos 	 *
1913a571abcSchristos 	 * !!!
1923a571abcSchristos 	 * If the entire replacement pattern is "%", then use the last
1933a571abcSchristos 	 * replacement pattern.  This semantic was added to vi in System
1943a571abcSchristos 	 * V and then percolated elsewhere, presumably around the time
1953a571abcSchristos 	 * that it was added to their version of ed(1).
1963a571abcSchristos 	 */
1973a571abcSchristos 	if (p[0] == L('\0') || p[0] == delim) {
1983a571abcSchristos 		if (p[0] == delim)
1993a571abcSchristos 			++p;
2003a571abcSchristos 		if (sp->repl != NULL)
2013a571abcSchristos 			free(sp->repl);
2023a571abcSchristos 		sp->repl = NULL;
2033a571abcSchristos 		sp->repl_len = 0;
2043a571abcSchristos 	} else if (p[0] == L('%') && (p[1] == L('\0') || p[1] == delim))
2053a571abcSchristos 		p += p[1] == delim ? 2 : 1;
2063a571abcSchristos 	else {
2073a571abcSchristos 		for (rep = p, len = 0;
2083a571abcSchristos 		    p[0] != L('\0') && p[0] != delim; ++p, ++len)
2093a571abcSchristos 			if (p[0] == L('~'))
2103a571abcSchristos 				len += sp->repl_len;
2113a571abcSchristos 		GET_SPACE_RETW(sp, bp, blen, len);
2123a571abcSchristos 		for (t = bp, len = 0, p = rep;;) {
2133a571abcSchristos 			if (p[0] == L('\0') || p[0] == delim) {
2143a571abcSchristos 				if (p[0] == delim)
2153a571abcSchristos 					++p;
2163a571abcSchristos 				break;
2173a571abcSchristos 			}
2183a571abcSchristos 			if (p[0] == L('\\')) {
2193a571abcSchristos 				if (p[1] == delim)
2203a571abcSchristos 					++p;
2213a571abcSchristos 				else if (p[1] == L('\\')) {
2223a571abcSchristos 					*t++ = *p++;
2233a571abcSchristos 					++len;
2243a571abcSchristos 				} else if (p[1] == L('~')) {
2253a571abcSchristos 					++p;
2263a571abcSchristos 					if (!O_ISSET(sp, O_MAGIC))
2273a571abcSchristos 						goto tilde;
2283a571abcSchristos 				}
2293a571abcSchristos 			} else if (p[0] == L('~') && O_ISSET(sp, O_MAGIC)) {
2303a571abcSchristos tilde:				++p;
2313a571abcSchristos 				MEMCPYW(t, sp->repl, sp->repl_len);
2323a571abcSchristos 				t += sp->repl_len;
2333a571abcSchristos 				len += sp->repl_len;
2343a571abcSchristos 				continue;
2353a571abcSchristos 			}
2363a571abcSchristos 			*t++ = *p++;
2373a571abcSchristos 			++len;
2383a571abcSchristos 		}
2393a571abcSchristos 		if ((sp->repl_len = len) != 0) {
2403a571abcSchristos 			if (sp->repl != NULL)
2413a571abcSchristos 				free(sp->repl);
2423a571abcSchristos 			if ((sp->repl = malloc(len * sizeof(CHAR_T))) == NULL) {
2433a571abcSchristos 				msgq(sp, M_SYSERR, NULL);
2443a571abcSchristos 				FREE_SPACEW(sp, bp, blen);
2453a571abcSchristos 				return (1);
2463a571abcSchristos 			}
2473a571abcSchristos 			MEMCPYW(sp->repl, bp, len);
2483a571abcSchristos 		}
2493a571abcSchristos 		FREE_SPACEW(sp, bp, blen);
2503a571abcSchristos 	}
2513a571abcSchristos 	return (s(sp, cmdp, p, re, flags));
2523a571abcSchristos }
2533a571abcSchristos 
2543a571abcSchristos /*
2553a571abcSchristos  * ex_subagain --
2563a571abcSchristos  *	[line [,line]] & [cgr] [count] [#lp]]
2573a571abcSchristos  *
2583a571abcSchristos  *	Substitute using the last substitute RE and replacement pattern.
2593a571abcSchristos  *
2603a571abcSchristos  * PUBLIC: int ex_subagain __P((SCR *, EXCMD *));
2613a571abcSchristos  */
2623a571abcSchristos int
ex_subagain(SCR * sp,EXCMD * cmdp)2633a571abcSchristos ex_subagain(SCR *sp, EXCMD *cmdp)
2643a571abcSchristos {
2653a571abcSchristos 	if (sp->subre == NULL) {
2663a571abcSchristos 		ex_emsg(sp, NULL, EXM_NOPREVRE);
2673a571abcSchristos 		return (1);
2683a571abcSchristos 	}
2693a571abcSchristos 	if (!F_ISSET(sp, SC_RE_SUBST) &&
2703a571abcSchristos 	    re_compile(sp, sp->subre, sp->subre_len,
2713a571abcSchristos 	    NULL, NULL, &sp->subre_c, SEARCH_CSUBST | SEARCH_MSG))
2723a571abcSchristos 		return (1);
2733a571abcSchristos 	return (s(sp,
2743a571abcSchristos 	    cmdp, cmdp->argc ? cmdp->argv[0]->bp : NULL, &sp->subre_c, 0));
2753a571abcSchristos }
2763a571abcSchristos 
2773a571abcSchristos /*
2783a571abcSchristos  * ex_subtilde --
2793a571abcSchristos  *	[line [,line]] ~ [cgr] [count] [#lp]]
2803a571abcSchristos  *
2813a571abcSchristos  *	Substitute using the last RE and last substitute replacement pattern.
2823a571abcSchristos  *
2833a571abcSchristos  * PUBLIC: int ex_subtilde __P((SCR *, EXCMD *));
2843a571abcSchristos  */
2853a571abcSchristos int
ex_subtilde(SCR * sp,EXCMD * cmdp)2863a571abcSchristos ex_subtilde(SCR *sp, EXCMD *cmdp)
2873a571abcSchristos {
2883a571abcSchristos 	if (sp->re == NULL) {
2893a571abcSchristos 		ex_emsg(sp, NULL, EXM_NOPREVRE);
2903a571abcSchristos 		return (1);
2913a571abcSchristos 	}
2923a571abcSchristos 	if (!F_ISSET(sp, SC_RE_SEARCH) && re_compile(sp, sp->re,
2933a571abcSchristos 	    sp->re_len, NULL, NULL, &sp->re_c, SEARCH_CSEARCH | SEARCH_MSG))
2943a571abcSchristos 		return (1);
2953a571abcSchristos 	return (s(sp,
2963a571abcSchristos 	    cmdp, cmdp->argc ? cmdp->argv[0]->bp : NULL, &sp->re_c, 0));
2973a571abcSchristos }
2983a571abcSchristos 
2993a571abcSchristos /*
3003a571abcSchristos  * s --
3013a571abcSchristos  * Do the substitution.  This stuff is *really* tricky.  There are lots of
3023a571abcSchristos  * special cases, and general nastiness.  Don't mess with it unless you're
3033a571abcSchristos  * pretty confident.
3043a571abcSchristos  *
3053a571abcSchristos  * The nasty part of the substitution is what happens when the replacement
3063a571abcSchristos  * string contains newlines.  It's a bit tricky -- consider the information
3073a571abcSchristos  * that has to be retained for "s/f\(o\)o/^M\1^M\1/".  The solution here is
3083a571abcSchristos  * to build a set of newline offsets which we use to break the line up later,
3093a571abcSchristos  * when the replacement is done.  Don't change it unless you're *damned*
3103a571abcSchristos  * confident.
3113a571abcSchristos  */
3123a571abcSchristos #define	NEEDNEWLINE(sp) {						\
3133a571abcSchristos 	if (sp->newl_len == sp->newl_cnt) {				\
3143a571abcSchristos 		sp->newl_len += 25;					\
3153a571abcSchristos 		REALLOC(sp, sp->newl, size_t *,				\
3163a571abcSchristos 		    sp->newl_len * sizeof(size_t));			\
3173a571abcSchristos 		if (sp->newl == NULL) {					\
3183a571abcSchristos 			sp->newl_len = 0;				\
3193a571abcSchristos 			return (1);					\
3203a571abcSchristos 		}							\
3213a571abcSchristos 	}								\
3223a571abcSchristos }
3233a571abcSchristos 
3243a571abcSchristos #define	BUILD(sp, l, len) {						\
3253a571abcSchristos 	if (lbclen + (len) > lblen) {					\
3263a571abcSchristos 		lblen += MAX(lbclen + (len), 256);			\
3273a571abcSchristos 		REALLOC(sp, lb, CHAR_T *, lblen * sizeof(CHAR_T));	\
3283a571abcSchristos 		if (lb == NULL) {					\
3293a571abcSchristos 			lbclen = 0;					\
3303a571abcSchristos 			return (1);					\
3313a571abcSchristos 		}							\
3323a571abcSchristos 	}								\
3333a571abcSchristos 	MEMCPYW(lb + lbclen, l, len);					\
3343a571abcSchristos 	lbclen += len;							\
3353a571abcSchristos }
3363a571abcSchristos 
3373a571abcSchristos #define	NEEDSP(sp, len, pnt) {						\
3383a571abcSchristos 	if (lbclen + (len) > lblen) {					\
3393a571abcSchristos 		lblen += MAX(lbclen + (len), 256);			\
3403a571abcSchristos 		REALLOC(sp, lb, CHAR_T *, lblen * sizeof(CHAR_T));	\
3413a571abcSchristos 		if (lb == NULL) {					\
3423a571abcSchristos 			lbclen = 0;					\
3433a571abcSchristos 			return (1);					\
3443a571abcSchristos 		}							\
3453a571abcSchristos 		pnt = lb + lbclen;					\
3463a571abcSchristos 	}								\
3473a571abcSchristos }
3483a571abcSchristos 
3493a571abcSchristos static int
s(SCR * sp,EXCMD * cmdp,CHAR_T * st,regex_t * re,u_int flags)35008d478e3Schristos s(SCR *sp, EXCMD *cmdp, CHAR_T *st, regex_t *re, u_int flags)
3513a571abcSchristos {
3523a571abcSchristos 	EVENT ev;
3533a571abcSchristos 	MARK from, to;
3543a571abcSchristos 	TEXTH tiq;
3553a571abcSchristos 	db_recno_t elno, lno, slno;
3563a571abcSchristos 	u_long ul;
3573a571abcSchristos 	regmatch_t match[10];
3583a571abcSchristos 	size_t blen, cnt, last, lbclen, lblen, len, llen;
3593a571abcSchristos 	size_t offset, saved_offset, scno;
36008d478e3Schristos 	int lflag, nflag, pflag, rflag;
3613a571abcSchristos 	int didsub, do_eol_match, eflags, empty_ok, eval;
3623a571abcSchristos 	int linechanged, matched, quit, rval;
36308d478e3Schristos 	CHAR_T *lb, *bp;
3643a571abcSchristos 	enum nresult nret;
3653a571abcSchristos 
3663a571abcSchristos 	NEEDFILE(sp, cmdp);
3673a571abcSchristos 
3683a571abcSchristos 	slno = sp->lno;
3693a571abcSchristos 	scno = sp->cno;
3703a571abcSchristos 
3713a571abcSchristos 	/*
3723a571abcSchristos 	 * !!!
3733a571abcSchristos 	 * Historically, the 'g' and 'c' suffices were always toggled as flags,
3743a571abcSchristos 	 * so ":s/A/B/" was the same as ":s/A/B/ccgg".  If O_EDCOMPATIBLE was
3753a571abcSchristos 	 * not set, they were initialized to 0 for all substitute commands.  If
3763a571abcSchristos 	 * O_EDCOMPATIBLE was set, they were initialized to 0 only if the user
3773a571abcSchristos 	 * specified substitute/replacement patterns (see ex_s()).
3783a571abcSchristos 	 */
3793a571abcSchristos 	if (!O_ISSET(sp, O_EDCOMPATIBLE))
3803a571abcSchristos 		sp->c_suffix = sp->g_suffix = 0;
3813a571abcSchristos 
3823a571abcSchristos 	/*
3833a571abcSchristos 	 * Historic vi permitted the '#', 'l' and 'p' options in vi mode, but
3843a571abcSchristos 	 * it only displayed the last change.  I'd disallow them, but they are
3853a571abcSchristos 	 * useful in combination with the [v]global commands.  In the current
3863a571abcSchristos 	 * model the problem is combining them with the 'c' flag -- the screen
3873a571abcSchristos 	 * would have to flip back and forth between the confirm screen and the
3883a571abcSchristos 	 * ex print screen, which would be pretty awful.  We do display all
3893a571abcSchristos 	 * changes, though, for what that's worth.
3903a571abcSchristos 	 *
3913a571abcSchristos 	 * !!!
3923a571abcSchristos 	 * Historic vi was fairly strict about the order of "options", the
3933a571abcSchristos 	 * count, and "flags".  I'm somewhat fuzzy on the difference between
3943a571abcSchristos 	 * options and flags, anyway, so this is a simpler approach, and we
3953a571abcSchristos 	 * just take it them in whatever order the user gives them.  (The ex
3963a571abcSchristos 	 * usage statement doesn't reflect this.)
3973a571abcSchristos 	 */
39808d478e3Schristos 	lflag = nflag = pflag = rflag = 0;
39908d478e3Schristos 	if (st == NULL)
4003a571abcSchristos 		goto noargs;
40108d478e3Schristos 	for (lno = OOBLNO; *st != '\0'; ++st)
40208d478e3Schristos 		switch (*st) {
4033a571abcSchristos 		case ' ':
4043a571abcSchristos 		case '\t':
4053a571abcSchristos 			continue;
4063a571abcSchristos 		case '+':
4073a571abcSchristos 			++cmdp->flagoff;
4083a571abcSchristos 			break;
4093a571abcSchristos 		case '-':
4103a571abcSchristos 			--cmdp->flagoff;
4113a571abcSchristos 			break;
4123a571abcSchristos 		case '0': case '1': case '2': case '3': case '4':
4133a571abcSchristos 		case '5': case '6': case '7': case '8': case '9':
4143a571abcSchristos 			if (lno != OOBLNO)
4153a571abcSchristos 				goto usage;
4163a571abcSchristos 			errno = 0;
41708d478e3Schristos 			nret = nget_uslong(sp, &ul, st, &st, 10);
4183a571abcSchristos 			lno = ul;
41908d478e3Schristos 			if (*st == '\0')		/* Loop increment correction. */
42008d478e3Schristos 				--st;
4213a571abcSchristos 			if (nret != NUM_OK) {
4223a571abcSchristos 				if (nret == NUM_OVER)
4233a571abcSchristos 					msgq(sp, M_ERR, "153|Count overflow");
4243a571abcSchristos 				else if (nret == NUM_UNDER)
4253a571abcSchristos 					msgq(sp, M_ERR, "154|Count underflow");
4263a571abcSchristos 				else
4273a571abcSchristos 					msgq(sp, M_SYSERR, NULL);
4283a571abcSchristos 				return (1);
4293a571abcSchristos 			}
4303a571abcSchristos 			/*
4313a571abcSchristos 			 * In historic vi, the count was inclusive from the
4323a571abcSchristos 			 * second address.
4333a571abcSchristos 			 */
4343a571abcSchristos 			cmdp->addr1.lno = cmdp->addr2.lno;
4353a571abcSchristos 			cmdp->addr2.lno += lno - 1;
4363a571abcSchristos 			if (!db_exist(sp, cmdp->addr2.lno) &&
4373a571abcSchristos 			    db_last(sp, &cmdp->addr2.lno))
4383a571abcSchristos 				return (1);
4393a571abcSchristos 			break;
4403a571abcSchristos 		case '#':
4413a571abcSchristos 			nflag = 1;
4423a571abcSchristos 			break;
4433a571abcSchristos 		case 'c':
4443a571abcSchristos 			sp->c_suffix = !sp->c_suffix;
4453a571abcSchristos 
4463a571abcSchristos 			/* Ex text structure initialization. */
4473a571abcSchristos 			if (F_ISSET(sp, SC_EX)) {
4483a571abcSchristos 				memset(&tiq, 0, sizeof(TEXTH));
4490b5c88f5Schristos 				TAILQ_INIT(&tiq);
4503a571abcSchristos 			}
4513a571abcSchristos 			break;
4523a571abcSchristos 		case 'g':
4533a571abcSchristos 			sp->g_suffix = !sp->g_suffix;
4543a571abcSchristos 			break;
4553a571abcSchristos 		case 'l':
4563a571abcSchristos 			lflag = 1;
4573a571abcSchristos 			break;
4583a571abcSchristos 		case 'p':
4593a571abcSchristos 			pflag = 1;
4603a571abcSchristos 			break;
4613a571abcSchristos 		case 'r':
4623a571abcSchristos 			if (LF_ISSET(SUB_FIRST)) {
4633a571abcSchristos 				msgq(sp, M_ERR,
4643a571abcSchristos 		    "155|Regular expression specified; r flag meaningless");
4653a571abcSchristos 				return (1);
4663a571abcSchristos 			}
4673a571abcSchristos 			if (!F_ISSET(sp, SC_RE_SEARCH)) {
4683a571abcSchristos 				ex_emsg(sp, NULL, EXM_NOPREVRE);
4693a571abcSchristos 				return (1);
4703a571abcSchristos 			}
4713a571abcSchristos 			rflag = 1;
4723a571abcSchristos 			re = &sp->re_c;
4733a571abcSchristos 			break;
4743a571abcSchristos 		default:
4753a571abcSchristos 			goto usage;
4763a571abcSchristos 		}
4773a571abcSchristos 
47808d478e3Schristos 	if (*st != '\0' || (!rflag && LF_ISSET(SUB_MUSTSETR))) {
4793a571abcSchristos usage:		ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
4803a571abcSchristos 		return (1);
4813a571abcSchristos 	}
4823a571abcSchristos 
4833a571abcSchristos noargs:	if (F_ISSET(sp, SC_VI) && sp->c_suffix && (lflag || nflag || pflag)) {
4843a571abcSchristos 		msgq(sp, M_ERR,
4853a571abcSchristos "156|The #, l and p flags may not be combined with the c flag in vi mode");
4863a571abcSchristos 		return (1);
4873a571abcSchristos 	}
4883a571abcSchristos 
4893a571abcSchristos 	/*
4903a571abcSchristos 	 * bp:		if interactive, line cache
4913a571abcSchristos 	 * blen:	if interactive, line cache length
4923a571abcSchristos 	 * lb:		build buffer pointer.
4933a571abcSchristos 	 * lbclen:	current length of built buffer.
4943a571abcSchristos 	 * lblen;	length of build buffer.
4953a571abcSchristos 	 */
4963a571abcSchristos 	bp = lb = NULL;
4973a571abcSchristos 	blen = lbclen = lblen = 0;
4983a571abcSchristos 
4993a571abcSchristos 	/* For each line... */
5003a571abcSchristos 	lno = cmdp->addr1.lno == 0 ? 1 : cmdp->addr1.lno;
5013a571abcSchristos 	for (matched = quit = 0,
5023a571abcSchristos 	    elno = cmdp->addr2.lno; !quit && lno <= elno; ++lno) {
5033a571abcSchristos 
5043a571abcSchristos 		/* Someone's unhappy, time to stop. */
5053a571abcSchristos 		if (INTERRUPTED(sp))
5063a571abcSchristos 			break;
5073a571abcSchristos 
5083a571abcSchristos 		/* Get the line. */
50908d478e3Schristos 		if (db_get(sp, lno, DBG_FATAL, &st, &llen))
5103a571abcSchristos 			goto err;
5113a571abcSchristos 
5123a571abcSchristos 		/*
5133a571abcSchristos 		 * Make a local copy if doing confirmation -- when calling
5143a571abcSchristos 		 * the confirm routine we're likely to lose the cached copy.
5153a571abcSchristos 		 */
5163a571abcSchristos 		if (sp->c_suffix) {
5173a571abcSchristos 			if (bp == NULL) {
5183a571abcSchristos 				GET_SPACE_RETW(sp, bp, blen, llen);
5193a571abcSchristos 			} else
5203a571abcSchristos 				ADD_SPACE_RETW(sp, bp, blen, llen);
52108d478e3Schristos 			MEMCPYW(bp, st, llen);
52208d478e3Schristos 			st = bp;
5233a571abcSchristos 		}
5243a571abcSchristos 
5253a571abcSchristos 		/* Start searching from the beginning. */
5263a571abcSchristos 		offset = 0;
5273a571abcSchristos 		len = llen;
5283a571abcSchristos 
5293a571abcSchristos 		/* Reset the build buffer offset. */
5303a571abcSchristos 		lbclen = 0;
5313a571abcSchristos 
5323a571abcSchristos 		/* Reset empty match flag. */
5333a571abcSchristos 		empty_ok = 1;
5343a571abcSchristos 
5353a571abcSchristos 		/*
5363a571abcSchristos 		 * We don't want to have to do a setline if the line didn't
5373a571abcSchristos 		 * change -- keep track of whether or not this line changed.
5383a571abcSchristos 		 * If doing confirmations, don't want to keep setting the
5393a571abcSchristos 		 * line if change is refused -- keep track of substitutions.
5403a571abcSchristos 		 */
5413a571abcSchristos 		didsub = linechanged = 0;
5423a571abcSchristos 
5433a571abcSchristos 		/* New line, do an EOL match. */
5443a571abcSchristos 		do_eol_match = 1;
5453a571abcSchristos 
5463a571abcSchristos 		/* It's not nul terminated, but we pretend it is. */
5473a571abcSchristos 		eflags = REG_STARTEND;
5483a571abcSchristos 
5493a571abcSchristos 		/*
55008d478e3Schristos 		 * The search area is from st + offset to the EOL.
5513a571abcSchristos 		 *
5523a571abcSchristos 		 * Generally, match[0].rm_so is the offset of the start
5533a571abcSchristos 		 * of the match from the start of the search, and offset
5543a571abcSchristos 		 * is the offset of the start of the last search.
5553a571abcSchristos 		 */
5563a571abcSchristos nextmatch:	match[0].rm_so = 0;
5573a571abcSchristos 		match[0].rm_eo = len;
5583a571abcSchristos 
5593a571abcSchristos 		/* Get the next match. */
56008d478e3Schristos 		eval = regexec(re, st + offset, 10, match, eflags);
5613a571abcSchristos 
5623a571abcSchristos 		/*
5633a571abcSchristos 		 * There wasn't a match or if there was an error, deal with
5643a571abcSchristos 		 * it.  If there was a previous match in this line, resolve
5653a571abcSchristos 		 * the changes into the database.  Otherwise, just move on.
5663a571abcSchristos 		 */
5673a571abcSchristos 		if (eval == REG_NOMATCH)
5683a571abcSchristos 			goto endmatch;
5693a571abcSchristos 		if (eval != 0) {
5703a571abcSchristos 			re_error(sp, eval, re);
5713a571abcSchristos 			goto err;
5723a571abcSchristos 		}
5733a571abcSchristos 		matched = 1;
5743a571abcSchristos 
5753a571abcSchristos 		/* Only the first search can match an anchored expression. */
5763a571abcSchristos 		eflags |= REG_NOTBOL;
5773a571abcSchristos 
5783a571abcSchristos 		/*
5793a571abcSchristos 		 * !!!
5803a571abcSchristos 		 * It's possible to match 0-length strings -- for example, the
5813a571abcSchristos 		 * command s;a*;X;, when matched against the string "aabb" will
5823a571abcSchristos 		 * result in "XbXbX", i.e. the matches are "aa", the space
5833a571abcSchristos 		 * between the b's and the space between the b's and the end of
5843a571abcSchristos 		 * the string.  There is a similar space between the beginning
5853a571abcSchristos 		 * of the string and the a's.  The rule that we use (because vi
5863a571abcSchristos 		 * historically used it) is that any 0-length match, occurring
5873a571abcSchristos 		 * immediately after a match, is ignored.  Otherwise, the above
5883a571abcSchristos 		 * example would have resulted in "XXbXbX".  Another example is
5893a571abcSchristos 		 * incorrectly using " *" to replace groups of spaces with one
5903a571abcSchristos 		 * space.
5913a571abcSchristos 		 *
5923a571abcSchristos 		 * The way we do this is that if we just had a successful match,
5933a571abcSchristos 		 * the starting offset does not skip characters, and the match
5943a571abcSchristos 		 * is empty, ignore the match and move forward.  If there's no
5953a571abcSchristos 		 * more characters in the string, we were attempting to match
5963a571abcSchristos 		 * after the last character, so quit.
5973a571abcSchristos 		 */
5983a571abcSchristos 		if (!empty_ok && match[0].rm_so == 0 && match[0].rm_eo == 0) {
5993a571abcSchristos 			empty_ok = 1;
6003a571abcSchristos 			if (len == 0)
6013a571abcSchristos 				goto endmatch;
60208d478e3Schristos 			BUILD(sp, st + offset, 1)
6033a571abcSchristos 			++offset;
6043a571abcSchristos 			--len;
6053a571abcSchristos 			goto nextmatch;
6063a571abcSchristos 		}
6073a571abcSchristos 
6083a571abcSchristos 		/* Confirm change. */
6093a571abcSchristos 		if (sp->c_suffix) {
6103a571abcSchristos 			/*
6113a571abcSchristos 			 * Set the cursor position for confirmation.  Note,
6123a571abcSchristos 			 * if we matched on a '$', the cursor may be past
6133a571abcSchristos 			 * the end of line.
6143a571abcSchristos 			 */
6153a571abcSchristos 			from.lno = to.lno = lno;
6163a571abcSchristos 			from.cno = match[0].rm_so + offset;
6173a571abcSchristos 			to.cno = match[0].rm_eo + offset;
6183a571abcSchristos 			/*
6193a571abcSchristos 			 * Both ex and vi have to correct for a change before
6203a571abcSchristos 			 * the first character in the line.
6213a571abcSchristos 			 */
6223a571abcSchristos 			if (llen == 0)
6233a571abcSchristos 				from.cno = to.cno = 0;
6243a571abcSchristos 			if (F_ISSET(sp, SC_VI)) {
6253a571abcSchristos 				/*
6263a571abcSchristos 				 * Only vi has to correct for a change after
6273a571abcSchristos 				 * the last character in the line.
6283a571abcSchristos 				 *
6293a571abcSchristos 				 * XXX
6303a571abcSchristos 				 * It would be nice to change the vi code so
6313a571abcSchristos 				 * that we could display a cursor past EOL.
6323a571abcSchristos 				 */
6333a571abcSchristos 				if (to.cno >= llen)
6343a571abcSchristos 					to.cno = llen - 1;
6353a571abcSchristos 				if (from.cno >= llen)
6363a571abcSchristos 					from.cno = llen - 1;
6373a571abcSchristos 
6383a571abcSchristos 				sp->lno = from.lno;
6393a571abcSchristos 				sp->cno = from.cno;
6403a571abcSchristos 				if (vs_refresh(sp, 1))
6413a571abcSchristos 					goto err;
6423a571abcSchristos 
6433a571abcSchristos 				vs_update(sp, msg_cat(sp,
6443a571abcSchristos 				    "169|Confirm change? [n]", NULL), NULL);
6453a571abcSchristos 
6463a571abcSchristos 				if (v_event_get(sp, &ev, 0, 0))
6473a571abcSchristos 					goto err;
6483a571abcSchristos 				switch (ev.e_event) {
6493a571abcSchristos 				case E_CHARACTER:
6503a571abcSchristos 					break;
6513a571abcSchristos 				case E_EOF:
6523a571abcSchristos 				case E_ERR:
6533a571abcSchristos 				case E_INTERRUPT:
6543a571abcSchristos 					goto lquit;
6553a571abcSchristos 				default:
6563a571abcSchristos 					v_event_err(sp, &ev);
6573a571abcSchristos 					goto lquit;
6583a571abcSchristos 				}
6593a571abcSchristos 			} else {
6603a571abcSchristos 				if (ex_print(sp, cmdp, &from, &to, 0) ||
6613a571abcSchristos 				    ex_scprint(sp, &from, &to))
6623a571abcSchristos 					goto lquit;
6633a571abcSchristos 				if (ex_txt(sp, &tiq, 0, TXT_CR))
6643a571abcSchristos 					goto err;
6650b5c88f5Schristos 				ev.e_c = TAILQ_FIRST(&tiq)->lb[0];
6663a571abcSchristos 			}
6673a571abcSchristos 
6683a571abcSchristos 			switch (ev.e_c) {
6693a571abcSchristos 			case CH_YES:
6703a571abcSchristos 				break;
6713a571abcSchristos 			default:
6723a571abcSchristos 			case CH_NO:
6733a571abcSchristos 				didsub = 0;
67408d478e3Schristos 				BUILD(sp, st + offset, match[0].rm_eo);
6753a571abcSchristos 				goto skip;
6763a571abcSchristos 			case CH_QUIT:
6773a571abcSchristos 				/* Set the quit/interrupted flags. */
6783a571abcSchristos lquit:				quit = 1;
6793a571abcSchristos 				F_SET(sp->gp, G_INTERRUPTED);
6803a571abcSchristos 
6813a571abcSchristos 				/*
6823a571abcSchristos 				 * Resolve any changes, then return to (and
6833a571abcSchristos 				 * exit from) the main loop.
6843a571abcSchristos 				 */
6853a571abcSchristos 				goto endmatch;
6863a571abcSchristos 			}
6873a571abcSchristos 		}
6883a571abcSchristos 
6893a571abcSchristos 		/*
6903a571abcSchristos 		 * Set the cursor to the last position changed, converting
6913a571abcSchristos 		 * from 1-based to 0-based.
6923a571abcSchristos 		 */
6933a571abcSchristos 		sp->lno = lno;
6943a571abcSchristos 		sp->cno = match[0].rm_so;
6953a571abcSchristos 
6963a571abcSchristos 		/* Copy the bytes before the match into the build buffer. */
69708d478e3Schristos 		BUILD(sp, st + offset, match[0].rm_so);
6983a571abcSchristos 
6993a571abcSchristos 		/* Substitute the matching bytes. */
7003a571abcSchristos 		didsub = 1;
70108d478e3Schristos 		if (re_sub(sp, st + offset, &lb, &lbclen, &lblen, match))
7023a571abcSchristos 			goto err;
7033a571abcSchristos 
7043a571abcSchristos 		/* Set the change flag so we know this line was modified. */
7053a571abcSchristos 		linechanged = 1;
7063a571abcSchristos 
7073a571abcSchristos 		/* Move past the matched bytes. */
7083a571abcSchristos skip:		offset += match[0].rm_eo;
7093a571abcSchristos 		len -= match[0].rm_eo;
7103a571abcSchristos 
7113a571abcSchristos 		/* A match cannot be followed by an empty pattern. */
7123a571abcSchristos 		empty_ok = 0;
7133a571abcSchristos 
7143a571abcSchristos 		/*
7153a571abcSchristos 		 * If doing a global change with confirmation, we have to
7163a571abcSchristos 		 * update the screen.  The basic idea is to store the line
7173a571abcSchristos 		 * so the screen update routines can find it, and restart.
7183a571abcSchristos 		 */
7193a571abcSchristos 		if (didsub && sp->c_suffix && sp->g_suffix) {
7203a571abcSchristos 			/*
7213a571abcSchristos 			 * The new search offset will be the end of the
7223a571abcSchristos 			 * modified line.
7233a571abcSchristos 			 */
7243a571abcSchristos 			saved_offset = lbclen;
7253a571abcSchristos 
7263a571abcSchristos 			/* Copy the rest of the line. */
7273a571abcSchristos 			if (len)
72808d478e3Schristos 				BUILD(sp, st + offset, len)
7293a571abcSchristos 
7303a571abcSchristos 			/* Set the new offset. */
7313a571abcSchristos 			offset = saved_offset;
7323a571abcSchristos 
7333a571abcSchristos 			/* Store inserted lines, adjusting the build buffer. */
7343a571abcSchristos 			last = 0;
7353a571abcSchristos 			if (sp->newl_cnt) {
7363a571abcSchristos 				for (cnt = 0;
7373a571abcSchristos 				    cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) {
7383a571abcSchristos 					if (db_insert(sp, lno,
7393a571abcSchristos 					    lb + last, sp->newl[cnt] - last))
7403a571abcSchristos 						goto err;
7413a571abcSchristos 					last = sp->newl[cnt] + 1;
7423a571abcSchristos 					++sp->rptlines[L_ADDED];
7433a571abcSchristos 				}
7443a571abcSchristos 				lbclen -= last;
7453a571abcSchristos 				offset -= last;
7463a571abcSchristos 				sp->newl_cnt = 0;
7473a571abcSchristos 			}
7483a571abcSchristos 
7493a571abcSchristos 			/* Store and retrieve the line. */
7503a571abcSchristos 			if (db_set(sp, lno, lb + last, lbclen))
7513a571abcSchristos 				goto err;
75208d478e3Schristos 			if (db_get(sp, lno, DBG_FATAL, &st, &llen))
7533a571abcSchristos 				goto err;
7543a571abcSchristos 			ADD_SPACE_RETW(sp, bp, blen, llen)
75508d478e3Schristos 			MEMCPYW(bp, st, llen);
75608d478e3Schristos 			st = bp;
7573a571abcSchristos 			len = llen - offset;
7583a571abcSchristos 
7593a571abcSchristos 			/* Restart the build. */
7603a571abcSchristos 			lbclen = 0;
76108d478e3Schristos 			BUILD(sp, st, offset);
7623a571abcSchristos 
7633a571abcSchristos 			/*
7643a571abcSchristos 			 * If we haven't already done the after-the-string
7653a571abcSchristos 			 * match, do one.  Set REG_NOTEOL so the '$' pattern
7663a571abcSchristos 			 * only matches once.
7673a571abcSchristos 			 */
7683a571abcSchristos 			if (!do_eol_match)
7693a571abcSchristos 				goto endmatch;
7703a571abcSchristos 			if (offset == len) {
7713a571abcSchristos 				do_eol_match = 0;
7723a571abcSchristos 				eflags |= REG_NOTEOL;
7733a571abcSchristos 			}
7743a571abcSchristos 			goto nextmatch;
7753a571abcSchristos 		}
7763a571abcSchristos 
7773a571abcSchristos 		/*
7783a571abcSchristos 		 * If it's a global:
7793a571abcSchristos 		 *
7803a571abcSchristos 		 * If at the end of the string, do a test for the after
7813a571abcSchristos 		 * the string match.  Set REG_NOTEOL so the '$' pattern
7823a571abcSchristos 		 * only matches once.
7833a571abcSchristos 		 */
7843a571abcSchristos 		if (sp->g_suffix && do_eol_match) {
7853a571abcSchristos 			if (len == 0) {
7863a571abcSchristos 				do_eol_match = 0;
7873a571abcSchristos 				eflags |= REG_NOTEOL;
7883a571abcSchristos 			}
7893a571abcSchristos 			goto nextmatch;
7903a571abcSchristos 		}
7913a571abcSchristos 
7923a571abcSchristos endmatch:	if (!linechanged)
7933a571abcSchristos 			continue;
7943a571abcSchristos 
7953a571abcSchristos 		/* Copy any remaining bytes into the build buffer. */
7963a571abcSchristos 		if (len)
79708d478e3Schristos 			BUILD(sp, st + offset, len)
7983a571abcSchristos 
7993a571abcSchristos 		/* Store inserted lines, adjusting the build buffer. */
8003a571abcSchristos 		last = 0;
8013a571abcSchristos 		if (sp->newl_cnt) {
8023a571abcSchristos 			for (cnt = 0;
8033a571abcSchristos 			    cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) {
8043a571abcSchristos 				if (db_insert(sp,
8053a571abcSchristos 				    lno, lb + last, sp->newl[cnt] - last))
8063a571abcSchristos 					goto err;
8073a571abcSchristos 				last = sp->newl[cnt] + 1;
8083a571abcSchristos 				++sp->rptlines[L_ADDED];
8093a571abcSchristos 			}
8103a571abcSchristos 			lbclen -= last;
8113a571abcSchristos 			sp->newl_cnt = 0;
8123a571abcSchristos 		}
8133a571abcSchristos 
8143a571abcSchristos 		/* Store the changed line. */
8153a571abcSchristos 		if (db_set(sp, lno, lb + last, lbclen))
8163a571abcSchristos 			goto err;
8173a571abcSchristos 
8183a571abcSchristos 		/* Update changed line counter. */
8193a571abcSchristos 		if (sp->rptlchange != lno) {
8203a571abcSchristos 			sp->rptlchange = lno;
8213a571abcSchristos 			++sp->rptlines[L_CHANGED];
8223a571abcSchristos 		}
8233a571abcSchristos 
8243a571abcSchristos 		/*
8253a571abcSchristos 		 * !!!
8263a571abcSchristos 		 * Display as necessary.  Historic practice is to only
8273a571abcSchristos 		 * display the last line of a line split into multiple
8283a571abcSchristos 		 * lines.
8293a571abcSchristos 		 */
8303a571abcSchristos 		if (lflag || nflag || pflag) {
8313a571abcSchristos 			from.lno = to.lno = lno;
8323a571abcSchristos 			from.cno = to.cno = 0;
8333a571abcSchristos 			if (lflag)
8343a571abcSchristos 				(void)ex_print(sp, cmdp, &from, &to, E_C_LIST);
8353a571abcSchristos 			if (nflag)
8363a571abcSchristos 				(void)ex_print(sp, cmdp, &from, &to, E_C_HASH);
8373a571abcSchristos 			if (pflag)
8383a571abcSchristos 				(void)ex_print(sp, cmdp, &from, &to, E_C_PRINT);
8393a571abcSchristos 		}
8403a571abcSchristos 	}
8413a571abcSchristos 
8423a571abcSchristos 	/*
8433a571abcSchristos 	 * !!!
8443a571abcSchristos 	 * Historically, vi attempted to leave the cursor at the same place if
8453a571abcSchristos 	 * the substitution was done at the current cursor position.  Otherwise
8463a571abcSchristos 	 * it moved it to the first non-blank of the last line changed.  There
8473a571abcSchristos 	 * were some problems: for example, :s/$/foo/ with the cursor on the
8483a571abcSchristos 	 * last character of the line left the cursor on the last character, or
8493a571abcSchristos 	 * the & command with multiple occurrences of the matching string in the
8503a571abcSchristos 	 * line usually left the cursor in a fairly random position.
8513a571abcSchristos 	 *
8523a571abcSchristos 	 * We try to do the same thing, with the exception that if the user is
8533a571abcSchristos 	 * doing substitution with confirmation, we move to the last line about
8543a571abcSchristos 	 * which the user was consulted, as opposed to the last line that they
8553a571abcSchristos 	 * actually changed.  This prevents a screen flash if the user doesn't
8563a571abcSchristos 	 * change many of the possible lines.
8573a571abcSchristos 	 */
8583a571abcSchristos 	if (!sp->c_suffix && (sp->lno != slno || sp->cno != scno)) {
8593a571abcSchristos 		sp->cno = 0;
8603a571abcSchristos 		(void)nonblank(sp, sp->lno, &sp->cno);
8613a571abcSchristos 	}
8623a571abcSchristos 
8633a571abcSchristos 	/*
8643a571abcSchristos 	 * If not in a global command, and nothing matched, say so.
8653a571abcSchristos 	 * Else, if none of the lines displayed, put something up.
8663a571abcSchristos 	 */
8673a571abcSchristos 	rval = 0;
8683a571abcSchristos 	if (!matched) {
8693a571abcSchristos 		if (!F_ISSET(sp, SC_EX_GLOBAL)) {
8703a571abcSchristos 			msgq(sp, M_ERR, "157|No match found");
8713a571abcSchristos 			goto err;
8723a571abcSchristos 		}
8733a571abcSchristos 	} else if (!lflag && !nflag && !pflag)
8743a571abcSchristos 		F_SET(cmdp, E_AUTOPRINT);
8753a571abcSchristos 
8763a571abcSchristos 	if (0) {
8773a571abcSchristos err:		rval = 1;
8783a571abcSchristos 	}
8793a571abcSchristos 
8803a571abcSchristos 	if (bp != NULL)
8813a571abcSchristos 		FREE_SPACEW(sp, bp, blen);
8823a571abcSchristos 	if (lb != NULL)
8833a571abcSchristos 		free(lb);
8843a571abcSchristos 	return (rval);
8853a571abcSchristos }
8863a571abcSchristos 
8873a571abcSchristos /*
8883a571abcSchristos  * re_compile --
8893a571abcSchristos  *	Compile the RE.
8903a571abcSchristos  *
8913a571abcSchristos  * PUBLIC: int re_compile __P((SCR *,
8923a571abcSchristos  * PUBLIC:     CHAR_T *, size_t, CHAR_T **, size_t *, regex_t *, u_int));
8933a571abcSchristos  */
8943a571abcSchristos int
re_compile(SCR * sp,CHAR_T * ptrn,size_t plen,CHAR_T ** ptrnp,size_t * lenp,regex_t * rep,u_int flags)8953a571abcSchristos re_compile(SCR *sp, CHAR_T *ptrn, size_t plen, CHAR_T **ptrnp, size_t *lenp, regex_t *rep, u_int flags)
8963a571abcSchristos {
8973a571abcSchristos 	size_t len;
8983a571abcSchristos 	int reflags, replaced, rval;
8993a571abcSchristos 	CHAR_T *p;
9003a571abcSchristos 
9013a571abcSchristos 	/* Set RE flags. */
9023a571abcSchristos 	reflags = 0;
9033a571abcSchristos 	if (LF_ISSET(SEARCH_EXTEND))
9043a571abcSchristos 		reflags |= REG_EXTENDED;
9053a571abcSchristos 	if (LF_ISSET(SEARCH_IC))
9063a571abcSchristos 		reflags |= REG_ICASE;
9073a571abcSchristos 	if (LF_ISSET(SEARCH_LITERAL))
9083a571abcSchristos 		reflags |= REG_NOSPEC;
9093a571abcSchristos 	if (!LF_ISSET(SEARCH_NOOPT | SEARCH_CSCOPE | SEARCH_TAG)) {
9103a571abcSchristos 		if (O_ISSET(sp, O_EXTENDED))
9113a571abcSchristos 			reflags |= REG_EXTENDED;
9123a571abcSchristos 		if (O_ISSET(sp, O_IGNORECASE))
9133a571abcSchristos 			reflags |= REG_ICASE;
9143a571abcSchristos 		if (O_ISSET(sp, O_ICLOWER))
9153a571abcSchristos 			goto iclower;
9163a571abcSchristos 	}
9173a571abcSchristos 	if (LF_ISSET(SEARCH_ICL)) {
9183a571abcSchristos iclower:	for (p = ptrn, len = plen; len > 0; ++p, --len)
91908d478e3Schristos 			if (ISUPPER((UCHAR_T)*p))
9203a571abcSchristos 				break;
9213a571abcSchristos 		if (len == 0)
9223a571abcSchristos 			reflags |= REG_ICASE;
9233a571abcSchristos 	}
9243a571abcSchristos 
9253a571abcSchristos 	/* If we're replacing a saved value, clear the old one. */
9263a571abcSchristos 	if (LF_ISSET(SEARCH_CSEARCH) && F_ISSET(sp, SC_RE_SEARCH)) {
9273a571abcSchristos 		regfree(&sp->re_c);
9283a571abcSchristos 		F_CLR(sp, SC_RE_SEARCH);
9293a571abcSchristos 	}
9303a571abcSchristos 	if (LF_ISSET(SEARCH_CSUBST) && F_ISSET(sp, SC_RE_SUBST)) {
9313a571abcSchristos 		regfree(&sp->subre_c);
9323a571abcSchristos 		F_CLR(sp, SC_RE_SUBST);
9333a571abcSchristos 	}
9343a571abcSchristos 
9353a571abcSchristos 	/*
9363a571abcSchristos 	 * If we're saving the string, it's a pattern we haven't seen before,
9373a571abcSchristos 	 * so convert the vi-style RE's to POSIX 1003.2 RE's.  Save a copy for
9383a571abcSchristos 	 * later recompilation.   Free any previously saved value.
9393a571abcSchristos 	 */
9403a571abcSchristos 	if (ptrnp != NULL) {
9413a571abcSchristos 		replaced = 0;
9423a571abcSchristos 		if (LF_ISSET(SEARCH_CSCOPE)) {
9433a571abcSchristos 			if (re_cscope_conv(sp, &ptrn, &plen, &replaced))
9443a571abcSchristos 				return (1);
9453a571abcSchristos 			/*
9463a571abcSchristos 			 * XXX
9473a571abcSchristos 			 * Currently, the match-any-<blank> expression used in
9483a571abcSchristos 			 * re_cscope_conv() requires extended RE's.  This may
9493a571abcSchristos 			 * not be right or safe.
9503a571abcSchristos 			 */
9513a571abcSchristos 			reflags |= REG_EXTENDED;
9523a571abcSchristos 		} else if (LF_ISSET(SEARCH_TAG)) {
9533a571abcSchristos 			if (re_tag_conv(sp, &ptrn, &plen, &replaced))
9543a571abcSchristos 				return (1);
9553a571abcSchristos 		} else if (!LF_ISSET(SEARCH_LITERAL))
9563a571abcSchristos 			if (re_conv(sp, &ptrn, &plen, &replaced))
9573a571abcSchristos 				return (1);
9583a571abcSchristos 
9593a571abcSchristos 		/* Discard previous pattern. */
9603a571abcSchristos 		if (*ptrnp != NULL) {
9613a571abcSchristos 			free(*ptrnp);
9623a571abcSchristos 			*ptrnp = NULL;
9633a571abcSchristos 		}
9643a571abcSchristos 		if (lenp != NULL)
9653a571abcSchristos 			*lenp = plen;
9663a571abcSchristos 
9673a571abcSchristos 		/*
9683a571abcSchristos 		 * Copy the string into allocated memory.
9693a571abcSchristos 		 *
9703a571abcSchristos 		 * XXX
9713a571abcSchristos 		 * Regcomp isn't 8-bit clean, so the pattern is nul-terminated
9723a571abcSchristos 		 * for now.  There's just no other solution.
9733a571abcSchristos 		 */
9743a571abcSchristos 		MALLOC(sp, *ptrnp, CHAR_T *, (plen + 1) * sizeof(CHAR_T));
9753a571abcSchristos 		if (*ptrnp != NULL) {
9763a571abcSchristos 			MEMCPYW(*ptrnp, ptrn, plen);
9773a571abcSchristos 			(*ptrnp)[plen] = '\0';
9783a571abcSchristos 		}
9793a571abcSchristos 
9803a571abcSchristos 		/* Free up conversion-routine-allocated memory. */
9813a571abcSchristos 		if (replaced)
9823a571abcSchristos 			FREE_SPACEW(sp, ptrn, 0);
9833a571abcSchristos 
9843a571abcSchristos 		if (*ptrnp == NULL)
9853a571abcSchristos 			return (1);
9863a571abcSchristos 
9873a571abcSchristos 		ptrn = *ptrnp;
9883a571abcSchristos 	}
9893a571abcSchristos 
9903a571abcSchristos 	/*
9913a571abcSchristos 	 * XXX
9923a571abcSchristos 	 * Regcomp isn't 8-bit clean, so we just lost if the pattern
9933a571abcSchristos 	 * contained a nul.  Bummer!
9943a571abcSchristos 	 */
9953a571abcSchristos 	if ((rval = regcomp(rep, ptrn, /* plen, */ reflags)) != 0) {
9963a571abcSchristos 		if (LF_ISSET(SEARCH_MSG))
9973a571abcSchristos 			re_error(sp, rval, rep);
9983a571abcSchristos 		return (1);
9993a571abcSchristos 	}
10003a571abcSchristos 
10013a571abcSchristos 	if (LF_ISSET(SEARCH_CSEARCH))
10023a571abcSchristos 		F_SET(sp, SC_RE_SEARCH);
10033a571abcSchristos 	if (LF_ISSET(SEARCH_CSUBST))
10043a571abcSchristos 		F_SET(sp, SC_RE_SUBST);
10053a571abcSchristos 
10063a571abcSchristos 	return (0);
10073a571abcSchristos }
10083a571abcSchristos 
10093a571abcSchristos /*
10103a571abcSchristos  * re_conv --
10113a571abcSchristos  *	Convert vi's regular expressions into something that the
10123a571abcSchristos  *	the POSIX 1003.2 RE functions can handle.
10133a571abcSchristos  *
10143a571abcSchristos  * There are three conversions we make to make vi's RE's (specifically
10153a571abcSchristos  * the global, search, and substitute patterns) work with POSIX RE's.
10163a571abcSchristos  *
10173a571abcSchristos  * 1: If O_MAGIC is not set, strip backslashes from the magic character
10183a571abcSchristos  *    set (.[*~) that have them, and add them to the ones that don't.
10193a571abcSchristos  * 2: If O_MAGIC is not set, the string "\~" is replaced with the text
10203a571abcSchristos  *    from the last substitute command's replacement string.  If O_MAGIC
10213a571abcSchristos  *    is set, it's the string "~".
10223a571abcSchristos  * 3: The pattern \<ptrn\> does "word" searches, convert it to use the
10233a571abcSchristos  *    new RE escapes.
10243a571abcSchristos  *
10253a571abcSchristos  * !!!/XXX
10263a571abcSchristos  * This doesn't exactly match the historic behavior of vi because we do
10273a571abcSchristos  * the ~ substitution before calling the RE engine, so magic characters
10283a571abcSchristos  * in the replacement string will be expanded by the RE engine, and they
10293a571abcSchristos  * weren't historically.  It's a bug.
10303a571abcSchristos  */
10313a571abcSchristos static int
re_conv(SCR * sp,CHAR_T ** ptrnp,size_t * plenp,int * replacedp)10323a571abcSchristos re_conv(SCR *sp, CHAR_T **ptrnp, size_t *plenp, int *replacedp)
10333a571abcSchristos {
10343a571abcSchristos 	size_t blen, len, needlen;
10353a571abcSchristos 	int magic;
10363a571abcSchristos 	CHAR_T *bp, *p, *t;
10373a571abcSchristos 
10383a571abcSchristos 	/*
10393a571abcSchristos 	 * First pass through, we figure out how much space we'll need.
10403a571abcSchristos 	 * We do it in two passes, on the grounds that most of the time
10413a571abcSchristos 	 * the user is doing a search and won't have magic characters.
10423a571abcSchristos 	 * That way we can skip most of the memory allocation and copies.
10433a571abcSchristos 	 */
10443a571abcSchristos 	magic = 0;
10453a571abcSchristos 	for (p = *ptrnp, len = *plenp, needlen = 0; len > 0; ++p, --len)
10463a571abcSchristos 		switch (*p) {
10473a571abcSchristos 		case '\\':
10483a571abcSchristos 			if (len > 1) {
10493a571abcSchristos 				--len;
10503a571abcSchristos 				switch (*++p) {
10513a571abcSchristos 				case '<':
10523a571abcSchristos 					magic = 1;
10533a571abcSchristos 					needlen += RE_WSTART_LEN + 1;
10543a571abcSchristos 					break;
10553a571abcSchristos 				case '>':
10563a571abcSchristos 					magic = 1;
10573a571abcSchristos 					needlen += RE_WSTOP_LEN + 1;
10583a571abcSchristos 					break;
10593a571abcSchristos 				case '~':
10603a571abcSchristos 					if (!O_ISSET(sp, O_MAGIC)) {
10613a571abcSchristos 						magic = 1;
10623a571abcSchristos 						needlen += sp->repl_len;
10633a571abcSchristos 					}
10643a571abcSchristos 					break;
10653a571abcSchristos 				case '.':
10663a571abcSchristos 				case '[':
10673a571abcSchristos 				case '*':
10683a571abcSchristos 					if (!O_ISSET(sp, O_MAGIC)) {
10693a571abcSchristos 						magic = 1;
10703a571abcSchristos 						needlen += 1;
10713a571abcSchristos 					}
10723a571abcSchristos 					break;
10733a571abcSchristos 				default:
10743a571abcSchristos 					needlen += 2;
10753a571abcSchristos 				}
10763a571abcSchristos 			} else
10773a571abcSchristos 				needlen += 1;
10783a571abcSchristos 			break;
10793a571abcSchristos 		case '~':
10803a571abcSchristos 			if (O_ISSET(sp, O_MAGIC)) {
10813a571abcSchristos 				magic = 1;
10823a571abcSchristos 				needlen += sp->repl_len;
10833a571abcSchristos 			}
10843a571abcSchristos 			break;
10853a571abcSchristos 		case '.':
10863a571abcSchristos 		case '[':
10873a571abcSchristos 		case '*':
10883a571abcSchristos 			if (!O_ISSET(sp, O_MAGIC)) {
10893a571abcSchristos 				magic = 1;
10903a571abcSchristos 				needlen += 2;
10913a571abcSchristos 			}
10923a571abcSchristos 			break;
10933a571abcSchristos 		default:
10943a571abcSchristos 			needlen += 1;
10953a571abcSchristos 			break;
10963a571abcSchristos 		}
10973a571abcSchristos 
10983a571abcSchristos 	if (!magic) {
10993a571abcSchristos 		*replacedp = 0;
11003a571abcSchristos 		return (0);
11013a571abcSchristos 	}
11023a571abcSchristos 
11033a571abcSchristos 	/* Get enough memory to hold the final pattern. */
11043a571abcSchristos 	*replacedp = 1;
11053a571abcSchristos 	GET_SPACE_RETW(sp, bp, blen, needlen);
11063a571abcSchristos 
11073a571abcSchristos 	for (p = *ptrnp, len = *plenp, t = bp; len > 0; ++p, --len)
11083a571abcSchristos 		switch (*p) {
11093a571abcSchristos 		case '\\':
11103a571abcSchristos 			if (len > 1) {
11113a571abcSchristos 				--len;
11123a571abcSchristos 				switch (*++p) {
11133a571abcSchristos 				case '<':
11143a571abcSchristos 					MEMCPY(t,
11153a571abcSchristos 					    RE_WSTART, RE_WSTART_LEN);
11163a571abcSchristos 					t += RE_WSTART_LEN;
11173a571abcSchristos 					break;
11183a571abcSchristos 				case '>':
11193a571abcSchristos 					MEMCPY(t,
11203a571abcSchristos 					    RE_WSTOP, RE_WSTOP_LEN);
11213a571abcSchristos 					t += RE_WSTOP_LEN;
11223a571abcSchristos 					break;
11233a571abcSchristos 				case '~':
11243a571abcSchristos 					if (O_ISSET(sp, O_MAGIC))
11253a571abcSchristos 						*t++ = '~';
11263a571abcSchristos 					else {
11273a571abcSchristos 						MEMCPYW(t,
11283a571abcSchristos 						    sp->repl, sp->repl_len);
11293a571abcSchristos 						t += sp->repl_len;
11303a571abcSchristos 					}
11313a571abcSchristos 					break;
11323a571abcSchristos 				case '.':
11333a571abcSchristos 				case '[':
11343a571abcSchristos 				case '*':
11353a571abcSchristos 					if (O_ISSET(sp, O_MAGIC))
11363a571abcSchristos 						*t++ = '\\';
11373a571abcSchristos 					*t++ = *p;
11383a571abcSchristos 					break;
11393a571abcSchristos 				default:
11403a571abcSchristos 					*t++ = '\\';
11413a571abcSchristos 					*t++ = *p;
11423a571abcSchristos 				}
11433a571abcSchristos 			} else
11443a571abcSchristos 				*t++ = '\\';
11453a571abcSchristos 			break;
11463a571abcSchristos 		case '~':
11473a571abcSchristos 			if (O_ISSET(sp, O_MAGIC)) {
11483a571abcSchristos 				MEMCPYW(t, sp->repl, sp->repl_len);
11493a571abcSchristos 				t += sp->repl_len;
11503a571abcSchristos 			} else
11513a571abcSchristos 				*t++ = '~';
11523a571abcSchristos 			break;
11533a571abcSchristos 		case '.':
11543a571abcSchristos 		case '[':
11553a571abcSchristos 		case '*':
11563a571abcSchristos 			if (!O_ISSET(sp, O_MAGIC))
11573a571abcSchristos 				*t++ = '\\';
11583a571abcSchristos 			*t++ = *p;
11593a571abcSchristos 			break;
11603a571abcSchristos 		default:
11613a571abcSchristos 			*t++ = *p;
11623a571abcSchristos 			break;
11633a571abcSchristos 		}
11643a571abcSchristos 
11653a571abcSchristos 	*ptrnp = bp;
11663a571abcSchristos 	*plenp = t - bp;
11673a571abcSchristos 	return (0);
11683a571abcSchristos }
11693a571abcSchristos 
11703a571abcSchristos /*
11713a571abcSchristos  * re_tag_conv --
11723a571abcSchristos  *	Convert a tags search path into something that the POSIX
11733a571abcSchristos  *	1003.2 RE functions can handle.
11743a571abcSchristos  */
11753a571abcSchristos static int
re_tag_conv(SCR * sp,CHAR_T ** ptrnp,size_t * plenp,int * replacedp)11763a571abcSchristos re_tag_conv(SCR *sp, CHAR_T **ptrnp, size_t *plenp, int *replacedp)
11773a571abcSchristos {
11783a571abcSchristos 	size_t blen, len;
11793a571abcSchristos 	int lastdollar;
11803a571abcSchristos 	CHAR_T *bp, *p, *t;
11813a571abcSchristos 
11823a571abcSchristos 	len = *plenp;
11833a571abcSchristos 
11843a571abcSchristos 	/* Max memory usage is 2 times the length of the string. */
11853a571abcSchristos 	*replacedp = 1;
11863a571abcSchristos 	GET_SPACE_RETW(sp, bp, blen, len * 2);
11873a571abcSchristos 
11883a571abcSchristos 	p = *ptrnp;
11893a571abcSchristos 	t = bp;
11903a571abcSchristos 
11913a571abcSchristos 	/* If the last character is a '/' or '?', we just strip it. */
11923a571abcSchristos 	if (len > 0 && (p[len - 1] == '/' || p[len - 1] == '?'))
11933a571abcSchristos 		--len;
11943a571abcSchristos 
11953a571abcSchristos 	/* If the next-to-last or last character is a '$', it's magic. */
11963a571abcSchristos 	if (len > 0 && p[len - 1] == '$') {
11973a571abcSchristos 		--len;
11983a571abcSchristos 		lastdollar = 1;
11993a571abcSchristos 	} else
12003a571abcSchristos 		lastdollar = 0;
12013a571abcSchristos 
12023a571abcSchristos 	/* If the first character is a '/' or '?', we just strip it. */
12033a571abcSchristos 	if (len > 0 && (p[0] == '/' || p[0] == '?')) {
12043a571abcSchristos 		++p;
12053a571abcSchristos 		--len;
12063a571abcSchristos 	}
12073a571abcSchristos 
12083a571abcSchristos 	/* If the first or second character is a '^', it's magic. */
12093a571abcSchristos 	if (p[0] == '^') {
12103a571abcSchristos 		*t++ = *p++;
12113a571abcSchristos 		--len;
12123a571abcSchristos 	}
12133a571abcSchristos 
12143a571abcSchristos 	/*
12153a571abcSchristos 	 * Escape every other magic character we can find, meanwhile stripping
12163a571abcSchristos 	 * the backslashes ctags inserts when escaping the search delimiter
12173a571abcSchristos 	 * characters.
12183a571abcSchristos 	 */
12193a571abcSchristos 	for (; len > 0; --len) {
12203a571abcSchristos 		if (p[0] == '\\' && (p[1] == '/' || p[1] == '?')) {
12213a571abcSchristos 			++p;
12223a571abcSchristos 			--len;
12233a571abcSchristos 		} else if (strchr("^.[]$*", p[0]))
12243a571abcSchristos 			*t++ = '\\';
12253a571abcSchristos 		*t++ = *p++;
12263a571abcSchristos 	}
12273a571abcSchristos 	if (lastdollar)
12283a571abcSchristos 		*t++ = '$';
12293a571abcSchristos 
12303a571abcSchristos 	*ptrnp = bp;
12313a571abcSchristos 	*plenp = t - bp;
12323a571abcSchristos 	return (0);
12333a571abcSchristos }
12343a571abcSchristos 
12353a571abcSchristos /*
12363a571abcSchristos  * re_cscope_conv --
12373a571abcSchristos  *	 Convert a cscope search path into something that the POSIX
12383a571abcSchristos  *      1003.2 RE functions can handle.
12393a571abcSchristos  */
12403a571abcSchristos static int
re_cscope_conv(SCR * sp,CHAR_T ** ptrnp,size_t * plenp,int * replacedp)12413a571abcSchristos re_cscope_conv(SCR *sp, CHAR_T **ptrnp, size_t *plenp, int *replacedp)
12423a571abcSchristos {
12433a571abcSchristos 	size_t blen, len, nspaces;
12443a571abcSchristos 	CHAR_T *bp, *t;
12453a571abcSchristos 	CHAR_T *p;
124608d478e3Schristos 	const CHAR_T *wp;
12473a571abcSchristos 	size_t wlen;
12483a571abcSchristos 
12493a571abcSchristos 	/*
12503a571abcSchristos 	 * Each space in the source line printed by cscope represents an
12513a571abcSchristos 	 * arbitrary sequence of spaces, tabs, and comments.
12523a571abcSchristos 	 */
12533a571abcSchristos #define	CSCOPE_RE_SPACE		"([ \t]|/\\*([^*]|\\*/)*\\*/)*"
12543a571abcSchristos #define CSCOPE_LEN	sizeof(CSCOPE_RE_SPACE) - 1
12553a571abcSchristos 	CHAR2INT(sp, CSCOPE_RE_SPACE, CSCOPE_LEN, wp, wlen);
12563a571abcSchristos 	for (nspaces = 0, p = *ptrnp, len = *plenp; len > 0; ++p, --len)
12573a571abcSchristos 		if (*p == ' ')
12583a571abcSchristos 			++nspaces;
12593a571abcSchristos 
12603a571abcSchristos 	/*
12613a571abcSchristos 	 * Allocate plenty of space:
12623a571abcSchristos 	 *	the string, plus potential escaping characters;
12633a571abcSchristos 	 *	nspaces + 2 copies of CSCOPE_RE_SPACE;
12643a571abcSchristos 	 *	^, $, nul terminator characters.
12653a571abcSchristos 	 */
12663a571abcSchristos 	*replacedp = 1;
12673a571abcSchristos 	len = (p - *ptrnp) * 2 + (nspaces + 2) * sizeof(CSCOPE_RE_SPACE) + 3;
12683a571abcSchristos 	GET_SPACE_RETW(sp, bp, blen, len);
12693a571abcSchristos 
12703a571abcSchristos 	p = *ptrnp;
12713a571abcSchristos 	t = bp;
12723a571abcSchristos 
12733a571abcSchristos 	*t++ = '^';
12743a571abcSchristos 	MEMCPYW(t, wp, wlen);
12753a571abcSchristos 	t += wlen;
12763a571abcSchristos 
12773a571abcSchristos 	for (len = *plenp; len > 0; ++p, --len)
12783a571abcSchristos 		if (*p == ' ') {
12793a571abcSchristos 			MEMCPYW(t, wp, wlen);
12803a571abcSchristos 			t += wlen;
12813a571abcSchristos 		} else {
12823a571abcSchristos 			if (strchr("\\^.[]$*+?()|{}", *p))
12833a571abcSchristos 				*t++ = '\\';
12843a571abcSchristos 			*t++ = *p;
12853a571abcSchristos 		}
12863a571abcSchristos 
12873a571abcSchristos 	MEMCPYW(t, wp, wlen);
12883a571abcSchristos 	t += wlen;
12893a571abcSchristos 	*t++ = '$';
12903a571abcSchristos 
12913a571abcSchristos 	*ptrnp = bp;
12923a571abcSchristos 	*plenp = t - bp;
12933a571abcSchristos 	return (0);
12943a571abcSchristos }
12953a571abcSchristos 
12963a571abcSchristos /*
12973a571abcSchristos  * re_error --
12983a571abcSchristos  *	Report a regular expression error.
12993a571abcSchristos  *
13003a571abcSchristos  * PUBLIC: void re_error __P((SCR *, int, regex_t *));
13013a571abcSchristos  */
13023a571abcSchristos void
re_error(SCR * sp,int errcode,regex_t * preg)13033a571abcSchristos re_error(SCR *sp, int errcode, regex_t *preg)
13043a571abcSchristos {
130508d478e3Schristos 	size_t sz;
13063a571abcSchristos 	char *oe;
13073a571abcSchristos 
130808d478e3Schristos 	sz = regerror(errcode, preg, NULL, 0);
130908d478e3Schristos 	if ((oe = malloc(sz)) == NULL)
13103a571abcSchristos 		msgq(sp, M_SYSERR, NULL);
13113a571abcSchristos 	else {
131208d478e3Schristos 		(void)regerror(errcode, preg, oe, sz);
13133a571abcSchristos 		msgq(sp, M_ERR, "RE error: %s", oe);
13143a571abcSchristos 		free(oe);
13153a571abcSchristos 	}
13163a571abcSchristos }
13173a571abcSchristos 
13183a571abcSchristos /*
13193a571abcSchristos  * re_sub --
13203a571abcSchristos  * 	Do the substitution for a regular expression.
13213a571abcSchristos  */
13223a571abcSchristos static int
re_sub(SCR * sp,CHAR_T * ip,CHAR_T ** lbp,size_t * lbclenp,size_t * lblenp,regmatch_t * match)13233a571abcSchristos re_sub(SCR *sp, CHAR_T *ip, CHAR_T **lbp, size_t *lbclenp, size_t *lblenp, regmatch_t *match)
13243a571abcSchristos 
13253a571abcSchristos 	           			/* Input line. */
13263a571abcSchristos 
13273a571abcSchristos 
13283a571abcSchristos 
13293a571abcSchristos {
133008d478e3Schristos 	enum { C_NOT_SET, C_LOWER, C_ONE_LOWER, C_ONE_UPPER, C_UPPER } conv;
13313a571abcSchristos 	size_t lbclen, lblen;		/* Local copies. */
13323a571abcSchristos 	size_t mlen;			/* Match length. */
13333a571abcSchristos 	size_t rpl;			/* Remaining replacement length. */
13343a571abcSchristos 	CHAR_T *rp;			/* Replacement pointer. */
13353a571abcSchristos 	int ch;
13363a571abcSchristos 	int no;				/* Match replacement offset. */
13373a571abcSchristos 	CHAR_T *p, *t;			/* Buffer pointers. */
13383a571abcSchristos 	CHAR_T *lb;			/* Local copies. */
13393a571abcSchristos 
13403a571abcSchristos 	lb = *lbp;			/* Get local copies. */
13413a571abcSchristos 	lbclen = *lbclenp;
13423a571abcSchristos 	lblen = *lblenp;
13433a571abcSchristos 
13443a571abcSchristos 	/*
13453a571abcSchristos 	 * QUOTING NOTE:
13463a571abcSchristos 	 *
13473a571abcSchristos 	 * There are some special sequences that vi provides in the
13483a571abcSchristos 	 * replacement patterns.
13493a571abcSchristos 	 *	 & string the RE matched (\& if nomagic set)
13503a571abcSchristos 	 *	\# n-th regular subexpression
13513a571abcSchristos 	 *	\E end \U, \L conversion
13523a571abcSchristos 	 *	\e end \U, \L conversion
13533a571abcSchristos 	 *	\l convert the next character to lower-case
13543a571abcSchristos 	 *	\L convert to lower-case, until \E, \e, or end of replacement
13553a571abcSchristos 	 *	\u convert the next character to upper-case
13563a571abcSchristos 	 *	\U convert to upper-case, until \E, \e, or end of replacement
13573a571abcSchristos 	 *
13583a571abcSchristos 	 * Otherwise, since this is the lowest level of replacement, discard
13593a571abcSchristos 	 * all escaping characters.  This (hopefully) matches historic practice.
13603a571abcSchristos 	 */
13613a571abcSchristos #define	OUTCH(ch, nltrans) {						\
136208d478e3Schristos 	ARG_CHAR_T __ch = (ch);						\
136308d478e3Schristos 	e_key_t __value = KEY_VAL(sp, __ch);				\
13643a571abcSchristos 	if (nltrans && (__value == K_CR || __value == K_NL)) {		\
13653a571abcSchristos 		NEEDNEWLINE(sp);					\
13663a571abcSchristos 		sp->newl[sp->newl_cnt++] = lbclen;			\
136708d478e3Schristos 	} else if (conv != C_NOT_SET) {					\
13683a571abcSchristos 		switch (conv) {						\
136908d478e3Schristos 		case C_ONE_LOWER:					\
137008d478e3Schristos 			conv = C_NOT_SET;				\
13713a571abcSchristos 			/* FALLTHROUGH */				\
13723a571abcSchristos 		case C_LOWER:						\
137308d478e3Schristos 			if (ISUPPER(__ch))				\
137408d478e3Schristos 				__ch = TOLOWER(__ch);			\
13753a571abcSchristos 			break;						\
137608d478e3Schristos 		case C_ONE_UPPER:					\
137708d478e3Schristos 			conv = C_NOT_SET;				\
13783a571abcSchristos 			/* FALLTHROUGH */				\
13793a571abcSchristos 		case C_UPPER:						\
138008d478e3Schristos 			if (ISLOWER(__ch))				\
138108d478e3Schristos 				__ch = TOUPPER(__ch);			\
13823a571abcSchristos 			break;						\
13833a571abcSchristos 		default:						\
13843a571abcSchristos 			abort();					\
13853a571abcSchristos 		}							\
13863a571abcSchristos 	}								\
13873a571abcSchristos 	NEEDSP(sp, 1, p);						\
13883a571abcSchristos 	*p++ = __ch;							\
13893a571abcSchristos 	++lbclen;							\
13903a571abcSchristos }
139108d478e3Schristos 	conv = C_NOT_SET;
13923a571abcSchristos 	for (rp = sp->repl, rpl = sp->repl_len, p = lb + lbclen; rpl--;) {
13933a571abcSchristos 		switch (ch = *rp++) {
13943a571abcSchristos 		case '&':
13953a571abcSchristos 			if (O_ISSET(sp, O_MAGIC)) {
13963a571abcSchristos 				no = 0;
13973a571abcSchristos 				goto subzero;
13983a571abcSchristos 			}
13993a571abcSchristos 			break;
14003a571abcSchristos 		case '\\':
14013a571abcSchristos 			if (rpl == 0)
14023a571abcSchristos 				break;
14033a571abcSchristos 			--rpl;
14043a571abcSchristos 			switch (ch = *rp) {
14053a571abcSchristos 			case '&':
14063a571abcSchristos 				++rp;
14073a571abcSchristos 				if (!O_ISSET(sp, O_MAGIC)) {
14083a571abcSchristos 					no = 0;
14093a571abcSchristos 					goto subzero;
14103a571abcSchristos 				}
14113a571abcSchristos 				break;
14123a571abcSchristos 			case '0': case '1': case '2': case '3': case '4':
14133a571abcSchristos 			case '5': case '6': case '7': case '8': case '9':
14143a571abcSchristos 				no = *rp++ - '0';
14153a571abcSchristos subzero:			if (match[no].rm_so == -1 ||
14163a571abcSchristos 			    	    match[no].rm_eo == -1)
14173a571abcSchristos 					break;
14183a571abcSchristos 				mlen = match[no].rm_eo - match[no].rm_so;
14193a571abcSchristos 				for (t = ip + match[no].rm_so; mlen--; ++t)
142008d478e3Schristos 					OUTCH((UCHAR_T)*t, 0);
14213a571abcSchristos 				continue;
14223a571abcSchristos 			case 'e':
14233a571abcSchristos 			case 'E':
14243a571abcSchristos 				++rp;
142508d478e3Schristos 				conv = C_NOT_SET;
14263a571abcSchristos 				continue;
14273a571abcSchristos 			case 'l':
14283a571abcSchristos 				++rp;
142908d478e3Schristos 				conv = C_ONE_LOWER;
14303a571abcSchristos 				continue;
14313a571abcSchristos 			case 'L':
14323a571abcSchristos 				++rp;
14333a571abcSchristos 				conv = C_LOWER;
14343a571abcSchristos 				continue;
14353a571abcSchristos 			case 'u':
14363a571abcSchristos 				++rp;
143708d478e3Schristos 				conv = C_ONE_UPPER;
14383a571abcSchristos 				continue;
14393a571abcSchristos 			case 'U':
14403a571abcSchristos 				++rp;
14413a571abcSchristos 				conv = C_UPPER;
14423a571abcSchristos 				continue;
14433a571abcSchristos 			default:
14443a571abcSchristos 				++rp;
14453a571abcSchristos 				break;
14463a571abcSchristos 			}
14473a571abcSchristos 		}
14483a571abcSchristos 		OUTCH(ch, 1);
14493a571abcSchristos 	}
14503a571abcSchristos 
14513a571abcSchristos 	*lbp = lb;			/* Update caller's information. */
14523a571abcSchristos 	*lbclenp = lbclen;
14533a571abcSchristos 	*lblenp = lblen;
14543a571abcSchristos 	return (0);
14553a571abcSchristos }
1456