xref: /titanic_50/usr/src/cmd/vi/port/ex_re.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*23a1cceaSRoger A. Faulkner  * Common Development and Distribution License (the "License").
6*23a1cceaSRoger A. Faulkner  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*23a1cceaSRoger A. Faulkner 
22f6db9f27Scf46844 /*
23*23a1cceaSRoger A. Faulkner  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24f6db9f27Scf46844  */
25f6db9f27Scf46844 
267c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
277c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include "ex.h"
337c478bd9Sstevel@tonic-gate #include "ex_re.h"
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate /* from libgen */
367c478bd9Sstevel@tonic-gate char *_compile(const char *, char *, char *, int);
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate  * The compiled-regular-expression storage areas (re, scanre, and subre)
407c478bd9Sstevel@tonic-gate  * have been changed into dynamically allocated memory areas, in both the
417c478bd9Sstevel@tonic-gate  * Solaris and XPG4 versions.
427c478bd9Sstevel@tonic-gate  *
437c478bd9Sstevel@tonic-gate  * In the Solaris version, which uses the original libgen(3g) compile()
447c478bd9Sstevel@tonic-gate  * and step() calls, these areas are allocated once, and then data are
457c478bd9Sstevel@tonic-gate  * copied between them subsequently, as they were in the original
467c478bd9Sstevel@tonic-gate  * implementation.  This is possible because the compiled information is
477c478bd9Sstevel@tonic-gate  * a self-contained block of bits.
487c478bd9Sstevel@tonic-gate  *
497c478bd9Sstevel@tonic-gate  * In the XPG4 version, the expr:compile.o object is linked in as a
507c478bd9Sstevel@tonic-gate  * simulation of these functions using the new regcomp() and regexec()
517c478bd9Sstevel@tonic-gate  * functions.  The problem here is that the resulting
527c478bd9Sstevel@tonic-gate  * compiled-regular-expression data contain pointers to other data, which
537c478bd9Sstevel@tonic-gate  * need to be freed, but only when we are quite sure that we are done
547c478bd9Sstevel@tonic-gate  * with them - and certainly not before.  There was an earlier attempt to
557c478bd9Sstevel@tonic-gate  * handle these differences, but that effort was flawed.
567c478bd9Sstevel@tonic-gate  */
577c478bd9Sstevel@tonic-gate 
58f6db9f27Scf46844 extern int	getchar();
597c478bd9Sstevel@tonic-gate #ifdef XPG4
607c478bd9Sstevel@tonic-gate void regex_comp_free(void *);
617c478bd9Sstevel@tonic-gate extern size_t regexc_size;	/* compile.c: size of regex_comp structure */
627c478bd9Sstevel@tonic-gate #endif /* XPG4 */
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate  * Global, substitute and regular expressions.
667c478bd9Sstevel@tonic-gate  * Very similar to ed, with some re extensions and
677c478bd9Sstevel@tonic-gate  * confirmed substitute.
687c478bd9Sstevel@tonic-gate  */
69f6db9f27Scf46844 void
global(k)707c478bd9Sstevel@tonic-gate global(k)
717c478bd9Sstevel@tonic-gate 	bool k;
727c478bd9Sstevel@tonic-gate {
737c478bd9Sstevel@tonic-gate 	unsigned char *gp;
747c478bd9Sstevel@tonic-gate 	int c;
757c478bd9Sstevel@tonic-gate 	line *a1;
767c478bd9Sstevel@tonic-gate 	unsigned char globuf[GBSIZE], *Cwas;
777c478bd9Sstevel@tonic-gate 	int nlines = lineDOL();
787c478bd9Sstevel@tonic-gate 	int oinglobal = inglobal;
797c478bd9Sstevel@tonic-gate 	unsigned char *oglobp = globp;
807c478bd9Sstevel@tonic-gate 	char	multi[MB_LEN_MAX + 1];
817c478bd9Sstevel@tonic-gate 	wchar_t	wc;
827c478bd9Sstevel@tonic-gate 	int	len;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	Cwas = Command;
867c478bd9Sstevel@tonic-gate 	/*
877c478bd9Sstevel@tonic-gate 	 * States of inglobal:
887c478bd9Sstevel@tonic-gate 	 *  0: ordinary - not in a global command.
897c478bd9Sstevel@tonic-gate 	 *  1: text coming from some buffer, not tty.
907c478bd9Sstevel@tonic-gate 	 *  2: like 1, but the source of the buffer is a global command.
917c478bd9Sstevel@tonic-gate 	 * Hence you're only in a global command if inglobal==2. This
927c478bd9Sstevel@tonic-gate 	 * strange sounding convention is historically derived from
937c478bd9Sstevel@tonic-gate 	 * everybody simulating a global command.
947c478bd9Sstevel@tonic-gate 	 */
957c478bd9Sstevel@tonic-gate 	if (inglobal==2)
967c478bd9Sstevel@tonic-gate 		error(value(vi_TERSE) ? gettext("Global within global") :
977c478bd9Sstevel@tonic-gate gettext("Global within global not allowed"));
987c478bd9Sstevel@tonic-gate 	markDOT();
997c478bd9Sstevel@tonic-gate 	setall();
1007c478bd9Sstevel@tonic-gate 	nonzero();
1017c478bd9Sstevel@tonic-gate 	if (skipend())
1027c478bd9Sstevel@tonic-gate 		error(value(vi_TERSE) ? gettext("Global needs re") :
1037c478bd9Sstevel@tonic-gate gettext("Missing regular expression for global"));
1047c478bd9Sstevel@tonic-gate 	c = getchar();
1057c478bd9Sstevel@tonic-gate 	(void)vi_compile(c, 1);
1067c478bd9Sstevel@tonic-gate 	savere(&scanre);
1077c478bd9Sstevel@tonic-gate 	gp = globuf;
1087c478bd9Sstevel@tonic-gate 	while ((c = peekchar()) != '\n') {
1097c478bd9Sstevel@tonic-gate 		if (!isascii(c)) {
1107c478bd9Sstevel@tonic-gate 			if (c == EOF) {
1117c478bd9Sstevel@tonic-gate 				c = '\n';
1127c478bd9Sstevel@tonic-gate 				ungetchar(c);
1137c478bd9Sstevel@tonic-gate 				goto out;
1147c478bd9Sstevel@tonic-gate 			}
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate mb_copy:
1177c478bd9Sstevel@tonic-gate 			if ((len = _mbftowc(multi, &wc, getchar, &peekc)) > 0) {
1187c478bd9Sstevel@tonic-gate 				if ((gp + len) >= &globuf[GBSIZE - 2])
1197c478bd9Sstevel@tonic-gate 					error(gettext("Global command too long"));
1207c478bd9Sstevel@tonic-gate 				strncpy(gp, multi, len);
1217c478bd9Sstevel@tonic-gate 				gp += len;
1227c478bd9Sstevel@tonic-gate 				continue;
1237c478bd9Sstevel@tonic-gate 			}
1247c478bd9Sstevel@tonic-gate 		}
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 		(void) getchar();
1277c478bd9Sstevel@tonic-gate 		switch (c) {
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 		case EOF:
1307c478bd9Sstevel@tonic-gate 			c = '\n';
1317c478bd9Sstevel@tonic-gate 			ungetchar(c);
1327c478bd9Sstevel@tonic-gate 			goto out;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 		case '\\':
1357c478bd9Sstevel@tonic-gate 			c = peekchar();
1367c478bd9Sstevel@tonic-gate 			if (!isascii(c)) {
1377c478bd9Sstevel@tonic-gate 				*gp++ = '\\';
1387c478bd9Sstevel@tonic-gate 				goto mb_copy;
1397c478bd9Sstevel@tonic-gate 			}
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 			(void) getchar();
1427c478bd9Sstevel@tonic-gate 			switch (c) {
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 			case '\\':
1457c478bd9Sstevel@tonic-gate 				ungetchar(c);
1467c478bd9Sstevel@tonic-gate 				break;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 			case '\n':
1497c478bd9Sstevel@tonic-gate 				break;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 			default:
1527c478bd9Sstevel@tonic-gate 				*gp++ = '\\';
1537c478bd9Sstevel@tonic-gate 				break;
1547c478bd9Sstevel@tonic-gate 			}
1557c478bd9Sstevel@tonic-gate 			break;
1567c478bd9Sstevel@tonic-gate 		}
1577c478bd9Sstevel@tonic-gate 		*gp++ = c;
1587c478bd9Sstevel@tonic-gate 		if (gp >= &globuf[GBSIZE - 2])
1597c478bd9Sstevel@tonic-gate 			error(gettext("Global command too long"));
1607c478bd9Sstevel@tonic-gate 	}
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate out:
1637c478bd9Sstevel@tonic-gate 	donewline();
1647c478bd9Sstevel@tonic-gate 	*gp++ = c;
1657c478bd9Sstevel@tonic-gate 	*gp++ = 0;
1667c478bd9Sstevel@tonic-gate 	saveall();
1677c478bd9Sstevel@tonic-gate 	inglobal = 2;
1687c478bd9Sstevel@tonic-gate 	for (a1 = one; a1 <= dol; a1++) {
1697c478bd9Sstevel@tonic-gate 		*a1 &= ~01;
1707c478bd9Sstevel@tonic-gate 		if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k)
1717c478bd9Sstevel@tonic-gate 			*a1 |= 01;
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate #ifdef notdef
1747c478bd9Sstevel@tonic-gate /*
1757c478bd9Sstevel@tonic-gate  * This code is commented out for now.  The problem is that we don't
1767c478bd9Sstevel@tonic-gate  * fix up the undo area the way we should.  Basically, I think what has
1777c478bd9Sstevel@tonic-gate  * to be done is to copy the undo area down (since we shrunk everything)
1787c478bd9Sstevel@tonic-gate  * and move the various pointers into it down too.  I will do this later
1797c478bd9Sstevel@tonic-gate  * when I have time. (Mark, 10-20-80)
1807c478bd9Sstevel@tonic-gate  */
1817c478bd9Sstevel@tonic-gate 	/*
1827c478bd9Sstevel@tonic-gate 	 * Special case: g/.../d (avoid n^2 algorithm)
1837c478bd9Sstevel@tonic-gate 	 */
1847c478bd9Sstevel@tonic-gate 	if (globuf[0]=='d' && globuf[1]=='\n' && globuf[2]=='\0') {
1857c478bd9Sstevel@tonic-gate 		gdelete();
1867c478bd9Sstevel@tonic-gate 		return;
1877c478bd9Sstevel@tonic-gate 	}
1887c478bd9Sstevel@tonic-gate #endif
1897c478bd9Sstevel@tonic-gate 	if (inopen)
1907c478bd9Sstevel@tonic-gate 		inopen = -1;
1917c478bd9Sstevel@tonic-gate 	/*
1927c478bd9Sstevel@tonic-gate 	 * Now for each marked line, set dot there and do the commands.
1937c478bd9Sstevel@tonic-gate 	 * Note the n^2 behavior here for lots of lines matching.
1947c478bd9Sstevel@tonic-gate 	 * This is really needed: in some cases you could delete lines,
1957c478bd9Sstevel@tonic-gate 	 * causing a marked line to be moved before a1 and missed if
1967c478bd9Sstevel@tonic-gate 	 * we didn't restart at zero each time.
1977c478bd9Sstevel@tonic-gate 	 */
1987c478bd9Sstevel@tonic-gate 	for (a1 = one; a1 <= dol; a1++) {
1997c478bd9Sstevel@tonic-gate 		if (*a1 & 01) {
2007c478bd9Sstevel@tonic-gate 			*a1 &= ~01;
2017c478bd9Sstevel@tonic-gate 			dot = a1;
2027c478bd9Sstevel@tonic-gate 			globp = globuf;
2037c478bd9Sstevel@tonic-gate 			commands(1, 1);
2047c478bd9Sstevel@tonic-gate 			a1 = zero;
2057c478bd9Sstevel@tonic-gate 		}
2067c478bd9Sstevel@tonic-gate 	}
2077c478bd9Sstevel@tonic-gate 	globp = oglobp;
2087c478bd9Sstevel@tonic-gate 	inglobal = oinglobal;
2097c478bd9Sstevel@tonic-gate 	endline = 1;
2107c478bd9Sstevel@tonic-gate 	Command = Cwas;
2117c478bd9Sstevel@tonic-gate 	netchHAD(nlines);
2127c478bd9Sstevel@tonic-gate 	setlastchar(EOF);
2137c478bd9Sstevel@tonic-gate 	if (inopen) {
2147c478bd9Sstevel@tonic-gate 		ungetchar(EOF);
2157c478bd9Sstevel@tonic-gate 		inopen = 1;
2167c478bd9Sstevel@tonic-gate 	}
2177c478bd9Sstevel@tonic-gate }
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate /*
2207c478bd9Sstevel@tonic-gate  * gdelete: delete inside a global command. Handles the
2217c478bd9Sstevel@tonic-gate  * special case g/r.e./d. All lines to be deleted have
2227c478bd9Sstevel@tonic-gate  * already been marked. Squeeze the remaining lines together.
2237c478bd9Sstevel@tonic-gate  * Note that other cases such as g/r.e./p, g/r.e./s/r.e.2/rhs/,
2247c478bd9Sstevel@tonic-gate  * and g/r.e./.,/r.e.2/d are not treated specially.  There is no
2257c478bd9Sstevel@tonic-gate  * good reason for this except the question: where to you draw the line?
2267c478bd9Sstevel@tonic-gate  */
227f6db9f27Scf46844 void
gdelete(void)228f6db9f27Scf46844 gdelete(void)
2297c478bd9Sstevel@tonic-gate {
2307c478bd9Sstevel@tonic-gate 	line *a1, *a2, *a3;
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	a3 = dol;
2337c478bd9Sstevel@tonic-gate 	/* find first marked line. can skip all before it */
2347c478bd9Sstevel@tonic-gate 	for (a1=zero; (*a1&01)==0; a1++)
2357c478bd9Sstevel@tonic-gate 		if (a1>=a3)
2367c478bd9Sstevel@tonic-gate 			return;
2377c478bd9Sstevel@tonic-gate 	/* copy down unmarked lines, compacting as we go. */
2387c478bd9Sstevel@tonic-gate 	for (a2=a1+1; a2<=a3;) {
2397c478bd9Sstevel@tonic-gate 		if (*a2&01) {
2407c478bd9Sstevel@tonic-gate 			a2++;		/* line is marked, skip it */
2417c478bd9Sstevel@tonic-gate 			dot = a1;	/* dot left after line deletion */
2427c478bd9Sstevel@tonic-gate 		} else
2437c478bd9Sstevel@tonic-gate 			*a1++ = *a2++;	/* unmarked, copy it */
2447c478bd9Sstevel@tonic-gate 	}
2457c478bd9Sstevel@tonic-gate 	dol = a1-1;
2467c478bd9Sstevel@tonic-gate 	if (dot>dol)
2477c478bd9Sstevel@tonic-gate 		dot = dol;
2487c478bd9Sstevel@tonic-gate 	change();
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate bool	cflag;
2527c478bd9Sstevel@tonic-gate int	scount, slines, stotal;
2537c478bd9Sstevel@tonic-gate 
254f6db9f27Scf46844 int
substitute(int c)255f6db9f27Scf46844 substitute(int c)
2567c478bd9Sstevel@tonic-gate {
2577c478bd9Sstevel@tonic-gate 	line *addr;
2587c478bd9Sstevel@tonic-gate 	int n;
2597c478bd9Sstevel@tonic-gate 	int gsubf, hopcount;
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	gsubf = compsub(c);
2627c478bd9Sstevel@tonic-gate 	if(FIXUNDO)
2637c478bd9Sstevel@tonic-gate 		save12(), undkind = UNDCHANGE;
2647c478bd9Sstevel@tonic-gate 	stotal = 0;
2657c478bd9Sstevel@tonic-gate 	slines = 0;
2667c478bd9Sstevel@tonic-gate 	for (addr = addr1; addr <= addr2; addr++) {
2677c478bd9Sstevel@tonic-gate 		scount = hopcount = 0;
2687c478bd9Sstevel@tonic-gate 		if (dosubcon(0, addr) == 0)
2697c478bd9Sstevel@tonic-gate 			continue;
2707c478bd9Sstevel@tonic-gate 		if (gsubf) {
2717c478bd9Sstevel@tonic-gate 			/*
2727c478bd9Sstevel@tonic-gate 			 * The loop can happen from s/\</&/g
2737c478bd9Sstevel@tonic-gate 			 * but we don't want to break other, reasonable cases.
2747c478bd9Sstevel@tonic-gate 			 */
2757c478bd9Sstevel@tonic-gate 			hopcount = 0;
2767c478bd9Sstevel@tonic-gate 			while (*loc2) {
2777c478bd9Sstevel@tonic-gate 				if (++hopcount > sizeof linebuf)
2787c478bd9Sstevel@tonic-gate 					error(gettext("substitution loop"));
2797c478bd9Sstevel@tonic-gate 				if (dosubcon(1, addr) == 0)
2807c478bd9Sstevel@tonic-gate 					break;
2817c478bd9Sstevel@tonic-gate 			}
2827c478bd9Sstevel@tonic-gate 		}
2837c478bd9Sstevel@tonic-gate 		if (scount) {
2847c478bd9Sstevel@tonic-gate 			stotal += scount;
2857c478bd9Sstevel@tonic-gate 			slines++;
2867c478bd9Sstevel@tonic-gate 			putmark(addr);
2877c478bd9Sstevel@tonic-gate 			n = append(getsub, addr);
2887c478bd9Sstevel@tonic-gate 			addr += n;
2897c478bd9Sstevel@tonic-gate 			addr2 += n;
2907c478bd9Sstevel@tonic-gate 		}
2917c478bd9Sstevel@tonic-gate 	}
2927c478bd9Sstevel@tonic-gate 	if (stotal == 0 && !inglobal && !cflag)
2937c478bd9Sstevel@tonic-gate 		error(value(vi_TERSE) ? gettext("Fail") :
2947c478bd9Sstevel@tonic-gate gettext("Substitute pattern match failed"));
2957c478bd9Sstevel@tonic-gate 	snote(stotal, slines);
2967c478bd9Sstevel@tonic-gate 	return (stotal);
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate 
299f6db9f27Scf46844 int
compsub(int ch)300f6db9f27Scf46844 compsub(int ch)
3017c478bd9Sstevel@tonic-gate {
3027c478bd9Sstevel@tonic-gate 	int seof, c, uselastre;
3037c478bd9Sstevel@tonic-gate 	static int gsubf;
3047c478bd9Sstevel@tonic-gate 	static unsigned char remem[RHSSIZE];
3057c478bd9Sstevel@tonic-gate 	static int remflg = -1;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	if (!value(vi_EDCOMPATIBLE))
3087c478bd9Sstevel@tonic-gate 		gsubf = cflag = 0;
3097c478bd9Sstevel@tonic-gate 	uselastre = 0;
3107c478bd9Sstevel@tonic-gate 	switch (ch) {
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	case 's':
3137c478bd9Sstevel@tonic-gate 		(void)skipwh();
3147c478bd9Sstevel@tonic-gate 		seof = getchar();
3157c478bd9Sstevel@tonic-gate 		if (endcmd(seof) || any(seof, "gcr")) {
3167c478bd9Sstevel@tonic-gate 			ungetchar(seof);
3177c478bd9Sstevel@tonic-gate 			goto redo;
3187c478bd9Sstevel@tonic-gate 		}
3197c478bd9Sstevel@tonic-gate 		if (isalpha(seof) || isdigit(seof))
3207c478bd9Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("Substitute needs re") :
3217c478bd9Sstevel@tonic-gate gettext("Missing regular expression for substitute"));
3227c478bd9Sstevel@tonic-gate 		seof = vi_compile(seof, 1);
3237c478bd9Sstevel@tonic-gate 		uselastre = 1;
3247c478bd9Sstevel@tonic-gate 		comprhs(seof);
3257c478bd9Sstevel@tonic-gate 		gsubf = cflag = 0;
3267c478bd9Sstevel@tonic-gate 		break;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	case '~':
3297c478bd9Sstevel@tonic-gate 		uselastre = 1;
3307c478bd9Sstevel@tonic-gate 		/* fall into ... */
3317c478bd9Sstevel@tonic-gate 	case '&':
3327c478bd9Sstevel@tonic-gate 	redo:
3337c478bd9Sstevel@tonic-gate 		if (re == NULL || re->Expbuf[1] == 0)
3347c478bd9Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("No previous re") :
3357c478bd9Sstevel@tonic-gate gettext("No previous regular expression"));
3367c478bd9Sstevel@tonic-gate 		if (subre == NULL || subre->Expbuf[1] == 0)
3377c478bd9Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("No previous substitute re") :
3387c478bd9Sstevel@tonic-gate gettext("No previous substitute to repeat"));
3397c478bd9Sstevel@tonic-gate 		break;
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 	for (;;) {
3427c478bd9Sstevel@tonic-gate 		c = getchar();
3437c478bd9Sstevel@tonic-gate 		switch (c) {
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 		case 'g':
3467c478bd9Sstevel@tonic-gate 			gsubf = !gsubf;
3477c478bd9Sstevel@tonic-gate 			continue;
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 		case 'c':
3507c478bd9Sstevel@tonic-gate 			cflag = !cflag;
3517c478bd9Sstevel@tonic-gate 			continue;
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 		case 'r':
3547c478bd9Sstevel@tonic-gate 			uselastre = 1;
3557c478bd9Sstevel@tonic-gate 			continue;
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 		default:
3587c478bd9Sstevel@tonic-gate 			ungetchar(c);
3597c478bd9Sstevel@tonic-gate 			setcount();
3607c478bd9Sstevel@tonic-gate 			donewline();
3617c478bd9Sstevel@tonic-gate 			if (uselastre)
3627c478bd9Sstevel@tonic-gate 				savere(&subre);
3637c478bd9Sstevel@tonic-gate 			else
3647c478bd9Sstevel@tonic-gate 				resre(subre);
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 			/*
3677c478bd9Sstevel@tonic-gate 			 * The % by itself on the right hand side means
3687c478bd9Sstevel@tonic-gate 			 * that the previous value of the right hand side
3697c478bd9Sstevel@tonic-gate 			 * should be used. A -1 is used to indicate no
3707c478bd9Sstevel@tonic-gate 			 * previously remembered search string.
3717c478bd9Sstevel@tonic-gate 			 */
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 			if (rhsbuf[0] == '%' && rhsbuf[1] == 0)
3747c478bd9Sstevel@tonic-gate 				if (remflg == -1)
3757c478bd9Sstevel@tonic-gate 					error(gettext("No previously remembered string"));
3767c478bd9Sstevel@tonic-gate 			        else
3777c478bd9Sstevel@tonic-gate 					strcpy(rhsbuf, remem);
3787c478bd9Sstevel@tonic-gate 			else {
3797c478bd9Sstevel@tonic-gate 				strcpy(remem, rhsbuf);
3807c478bd9Sstevel@tonic-gate 				remflg = 1;
3817c478bd9Sstevel@tonic-gate 			}
3827c478bd9Sstevel@tonic-gate 			return (gsubf);
3837c478bd9Sstevel@tonic-gate 		}
3847c478bd9Sstevel@tonic-gate 	}
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate 
387f6db9f27Scf46844 void
comprhs(int seof)388f6db9f27Scf46844 comprhs(int seof)
3897c478bd9Sstevel@tonic-gate {
3907c478bd9Sstevel@tonic-gate 	unsigned char *rp, *orp;
3917c478bd9Sstevel@tonic-gate 	int c;
3927c478bd9Sstevel@tonic-gate 	unsigned char orhsbuf[RHSSIZE];
3937c478bd9Sstevel@tonic-gate 	char	multi[MB_LEN_MAX + 1];
3947c478bd9Sstevel@tonic-gate 	int	len;
3957c478bd9Sstevel@tonic-gate 	wchar_t	wc;
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	rp = rhsbuf;
3987c478bd9Sstevel@tonic-gate 	CP(orhsbuf, rp);
3997c478bd9Sstevel@tonic-gate 	for (;;) {
4007c478bd9Sstevel@tonic-gate 		c = peekchar();
4017c478bd9Sstevel@tonic-gate 		if (c == seof) {
4027c478bd9Sstevel@tonic-gate 			(void) getchar();
4037c478bd9Sstevel@tonic-gate 			break;
4047c478bd9Sstevel@tonic-gate 		}
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 		if (!isascii(c) && c != EOF) {
4077c478bd9Sstevel@tonic-gate 			if ((len = _mbftowc(multi, &wc, getchar, &peekc)) > 0) {
4087c478bd9Sstevel@tonic-gate 				if ((rp + len) >= &rhsbuf[RHSSIZE - 1])
4097c478bd9Sstevel@tonic-gate 					goto toobig;
4107c478bd9Sstevel@tonic-gate 				strncpy(rp, multi, len);
4117c478bd9Sstevel@tonic-gate 				rp += len;
4127c478bd9Sstevel@tonic-gate 				continue;
4137c478bd9Sstevel@tonic-gate 			}
4147c478bd9Sstevel@tonic-gate 		}
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 		(void) getchar();
4177c478bd9Sstevel@tonic-gate 		switch (c) {
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 		case '\\':
4207c478bd9Sstevel@tonic-gate 			c = peekchar();
4217c478bd9Sstevel@tonic-gate 			if (c == EOF) {
4227c478bd9Sstevel@tonic-gate 				(void) getchar();
4237c478bd9Sstevel@tonic-gate 				error(gettext("Replacement string ends with \\"));
4247c478bd9Sstevel@tonic-gate 			}
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 			if (!isascii(c)) {
4277c478bd9Sstevel@tonic-gate 				*rp++ = '\\';
4287c478bd9Sstevel@tonic-gate 				if ((len = _mbftowc(multi, &wc, getchar, &peekc)) > 0) {
4297c478bd9Sstevel@tonic-gate 					if ((rp + len) >= &rhsbuf[RHSSIZE - 1])
4307c478bd9Sstevel@tonic-gate 						goto over_flow;
4317c478bd9Sstevel@tonic-gate 					strncpy(rp, multi, len);
4327c478bd9Sstevel@tonic-gate 					rp += len;
4337c478bd9Sstevel@tonic-gate 					continue;
4347c478bd9Sstevel@tonic-gate 				}
4357c478bd9Sstevel@tonic-gate 			}
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 			(void) getchar();
4387c478bd9Sstevel@tonic-gate 			if (value(vi_MAGIC)) {
4397c478bd9Sstevel@tonic-gate 				/*
4407c478bd9Sstevel@tonic-gate 				 * When "magic", \& turns into a plain &,
4417c478bd9Sstevel@tonic-gate 				 * and all other chars work fine quoted.
4427c478bd9Sstevel@tonic-gate 				 */
4437c478bd9Sstevel@tonic-gate 				if (c != '&') {
4447c478bd9Sstevel@tonic-gate 					if(rp >= &rhsbuf[RHSSIZE - 1]) {
4457c478bd9Sstevel@tonic-gate 						*rp=0;
4467c478bd9Sstevel@tonic-gate 						error(value(vi_TERSE) ?
4477c478bd9Sstevel@tonic-gate gettext("Replacement pattern too long") :
4487c478bd9Sstevel@tonic-gate gettext("Replacement pattern too long - limit 256 characters"));
4497c478bd9Sstevel@tonic-gate 					}
4507c478bd9Sstevel@tonic-gate 					*rp++ = '\\';
4517c478bd9Sstevel@tonic-gate 				}
4527c478bd9Sstevel@tonic-gate 				break;
4537c478bd9Sstevel@tonic-gate 			}
4547c478bd9Sstevel@tonic-gate magic:
4557c478bd9Sstevel@tonic-gate 			if (c == '~') {
4567c478bd9Sstevel@tonic-gate 				for (orp = orhsbuf; *orp; *rp++ = *orp++)
4577c478bd9Sstevel@tonic-gate 					if (rp >= &rhsbuf[RHSSIZE - 1])
4587c478bd9Sstevel@tonic-gate 						goto toobig;
4597c478bd9Sstevel@tonic-gate 				continue;
4607c478bd9Sstevel@tonic-gate 			}
4617c478bd9Sstevel@tonic-gate 			if(rp >= &rhsbuf[RHSSIZE - 1]) {
4627c478bd9Sstevel@tonic-gate over_flow:
4637c478bd9Sstevel@tonic-gate 				*rp=0;
4647c478bd9Sstevel@tonic-gate 				error(value(vi_TERSE) ?
4657c478bd9Sstevel@tonic-gate gettext("Replacement pattern too long") :
4667c478bd9Sstevel@tonic-gate gettext("Replacement pattern too long - limit 256 characters"));
4677c478bd9Sstevel@tonic-gate 			}
4687c478bd9Sstevel@tonic-gate 			*rp++ = '\\';
4697c478bd9Sstevel@tonic-gate 			break;
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 		case '\n':
4727c478bd9Sstevel@tonic-gate 		case EOF:
4737c478bd9Sstevel@tonic-gate 			if (!(globp && globp[0])) {
4747c478bd9Sstevel@tonic-gate 				ungetchar(c);
4757c478bd9Sstevel@tonic-gate 				goto endrhs;
4767c478bd9Sstevel@tonic-gate 			}
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 		case '~':
4797c478bd9Sstevel@tonic-gate 		case '&':
4807c478bd9Sstevel@tonic-gate 			if (value(vi_MAGIC))
4817c478bd9Sstevel@tonic-gate 				goto magic;
4827c478bd9Sstevel@tonic-gate 			break;
4837c478bd9Sstevel@tonic-gate 		}
4847c478bd9Sstevel@tonic-gate 		if (rp >= &rhsbuf[RHSSIZE - 1]) {
4857c478bd9Sstevel@tonic-gate toobig:
4867c478bd9Sstevel@tonic-gate 			*rp = 0;
4877c478bd9Sstevel@tonic-gate 			error(value(vi_TERSE) ?
4887c478bd9Sstevel@tonic-gate gettext("Replacement pattern too long") :
4897c478bd9Sstevel@tonic-gate gettext("Replacement pattern too long - limit 256 characters"));
4907c478bd9Sstevel@tonic-gate 		}
4917c478bd9Sstevel@tonic-gate 		*rp++ = c;
4927c478bd9Sstevel@tonic-gate 	}
4937c478bd9Sstevel@tonic-gate endrhs:
4947c478bd9Sstevel@tonic-gate 	*rp++ = 0;
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate 
497f6db9f27Scf46844 int
getsub(void)498f6db9f27Scf46844 getsub(void)
4997c478bd9Sstevel@tonic-gate {
5007c478bd9Sstevel@tonic-gate 	unsigned char *p;
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	if ((p = linebp) == 0)
5037c478bd9Sstevel@tonic-gate 		return (EOF);
5047c478bd9Sstevel@tonic-gate 	strcLIN(p);
5057c478bd9Sstevel@tonic-gate 	linebp = 0;
5067c478bd9Sstevel@tonic-gate 	return (0);
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate 
509f6db9f27Scf46844 int
dosubcon(bool f,line * a)510f6db9f27Scf46844 dosubcon(bool f, line *a)
5117c478bd9Sstevel@tonic-gate {
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	if (execute(f, a) == 0)
5147c478bd9Sstevel@tonic-gate 		return (0);
5157c478bd9Sstevel@tonic-gate 	if (confirmed(a)) {
5167c478bd9Sstevel@tonic-gate 		dosub();
5177c478bd9Sstevel@tonic-gate 		scount++;
5187c478bd9Sstevel@tonic-gate 	}
5197c478bd9Sstevel@tonic-gate 	return (1);
5207c478bd9Sstevel@tonic-gate }
5217c478bd9Sstevel@tonic-gate 
522f6db9f27Scf46844 int
confirmed(line * a)523f6db9f27Scf46844 confirmed(line *a)
5247c478bd9Sstevel@tonic-gate {
5257c478bd9Sstevel@tonic-gate 	int c, cnt, ch;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	if (cflag == 0)
5287c478bd9Sstevel@tonic-gate 		return (1);
5297c478bd9Sstevel@tonic-gate 	pofix();
5307c478bd9Sstevel@tonic-gate 	pline(lineno(a));
5317c478bd9Sstevel@tonic-gate 	if (inopen)
5327c478bd9Sstevel@tonic-gate 		putchar('\n' | QUOTE);
5337c478bd9Sstevel@tonic-gate 	c = lcolumn(loc1);
5347c478bd9Sstevel@tonic-gate 	ugo(c, ' ');
5357c478bd9Sstevel@tonic-gate 	ugo(lcolumn(loc2) - c, '^');
5367c478bd9Sstevel@tonic-gate 	flush();
5377c478bd9Sstevel@tonic-gate 	cnt = 0;
5387c478bd9Sstevel@tonic-gate bkup:
5397c478bd9Sstevel@tonic-gate 	ch = c = getkey();
5407c478bd9Sstevel@tonic-gate again:
5417c478bd9Sstevel@tonic-gate 	if (c == '\b') {
5427c478bd9Sstevel@tonic-gate 		if ((inopen)
5437c478bd9Sstevel@tonic-gate 		 && (cnt > 0)) {
5447c478bd9Sstevel@tonic-gate 			putchar('\b' | QUOTE);
5457c478bd9Sstevel@tonic-gate 			putchar(' ');
5467c478bd9Sstevel@tonic-gate 			putchar('\b' | QUOTE), flush();
5477c478bd9Sstevel@tonic-gate 			cnt --;
5487c478bd9Sstevel@tonic-gate 		}
5497c478bd9Sstevel@tonic-gate 		goto bkup;
5507c478bd9Sstevel@tonic-gate 	}
5517c478bd9Sstevel@tonic-gate 	if (c == '\r')
5527c478bd9Sstevel@tonic-gate 		c = '\n';
5537c478bd9Sstevel@tonic-gate 	if (inopen && MB_CUR_MAX == 1 || c < 0200) {
5547c478bd9Sstevel@tonic-gate 		putchar(c);
5557c478bd9Sstevel@tonic-gate 		flush();
5567c478bd9Sstevel@tonic-gate 		cnt++;
5577c478bd9Sstevel@tonic-gate 	}
5587c478bd9Sstevel@tonic-gate 	if (c != '\n' && c != EOF) {
5597c478bd9Sstevel@tonic-gate 		c = getkey();
5607c478bd9Sstevel@tonic-gate 		goto again;
5617c478bd9Sstevel@tonic-gate 	}
5627c478bd9Sstevel@tonic-gate 	noteinp();
5637c478bd9Sstevel@tonic-gate 	return (ch == 'y');
5647c478bd9Sstevel@tonic-gate }
5657c478bd9Sstevel@tonic-gate 
566f6db9f27Scf46844 void
ugo(int cnt,int with)567f6db9f27Scf46844 ugo(int cnt, int with)
5687c478bd9Sstevel@tonic-gate {
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	if (cnt > 0)
5717c478bd9Sstevel@tonic-gate 		do
5727c478bd9Sstevel@tonic-gate 			putchar(with);
5737c478bd9Sstevel@tonic-gate 		while (--cnt > 0);
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate int	casecnt;
5777c478bd9Sstevel@tonic-gate bool	destuc;
5787c478bd9Sstevel@tonic-gate 
579f6db9f27Scf46844 void
dosub(void)580f6db9f27Scf46844 dosub(void)
5817c478bd9Sstevel@tonic-gate {
5827c478bd9Sstevel@tonic-gate 	unsigned char *lp, *sp, *rp;
5837c478bd9Sstevel@tonic-gate 	int c;
5847c478bd9Sstevel@tonic-gate 	int	len;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	lp = linebuf;
5877c478bd9Sstevel@tonic-gate 	sp = genbuf;
5887c478bd9Sstevel@tonic-gate 	rp = rhsbuf;
5897c478bd9Sstevel@tonic-gate 	while (lp < (unsigned char *)loc1)
5907c478bd9Sstevel@tonic-gate 		*sp++ = *lp++;
5917c478bd9Sstevel@tonic-gate 	casecnt = 0;
5927c478bd9Sstevel@tonic-gate 	/*
5937c478bd9Sstevel@tonic-gate 	 * Caution: depending on the hardware, c will be either sign
5947c478bd9Sstevel@tonic-gate 	 * extended or not if C&QUOTE is set.  Thus, on a VAX, c will
5957c478bd9Sstevel@tonic-gate 	 * be < 0, but on a 3B, c will be >= 128.
5967c478bd9Sstevel@tonic-gate 	 */
5977c478bd9Sstevel@tonic-gate 	while (c = *rp) {
5987c478bd9Sstevel@tonic-gate 		if ((len = mblen((char *)rp, MB_CUR_MAX)) <= 0)
5997c478bd9Sstevel@tonic-gate 			len = 1;
6007c478bd9Sstevel@tonic-gate 		/* ^V <return> from vi to split lines */
6017c478bd9Sstevel@tonic-gate 		if (c == '\r')
6027c478bd9Sstevel@tonic-gate 			c = '\n';
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 		if (c == '\\') {
6057c478bd9Sstevel@tonic-gate 			rp++;
6067c478bd9Sstevel@tonic-gate 			if ((len = mblen((char *)rp, MB_CUR_MAX)) <= 0)
6077c478bd9Sstevel@tonic-gate 				len = 1;
6087c478bd9Sstevel@tonic-gate 			switch (c = *rp++) {
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 			case '&':
6117c478bd9Sstevel@tonic-gate 				sp = place(sp, loc1, loc2);
6127c478bd9Sstevel@tonic-gate 				if (sp == 0)
6137c478bd9Sstevel@tonic-gate 					goto ovflo;
6147c478bd9Sstevel@tonic-gate 				continue;
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 			case 'l':
6177c478bd9Sstevel@tonic-gate 				casecnt = 1;
6187c478bd9Sstevel@tonic-gate 				destuc = 0;
6197c478bd9Sstevel@tonic-gate 				continue;
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 			case 'L':
6227c478bd9Sstevel@tonic-gate 				casecnt = LBSIZE;
6237c478bd9Sstevel@tonic-gate 				destuc = 0;
6247c478bd9Sstevel@tonic-gate 				continue;
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 			case 'u':
6277c478bd9Sstevel@tonic-gate 				casecnt = 1;
6287c478bd9Sstevel@tonic-gate 				destuc = 1;
6297c478bd9Sstevel@tonic-gate 				continue;
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 			case 'U':
6327c478bd9Sstevel@tonic-gate 				casecnt = LBSIZE;
6337c478bd9Sstevel@tonic-gate 				destuc = 1;
6347c478bd9Sstevel@tonic-gate 				continue;
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 			case 'E':
6377c478bd9Sstevel@tonic-gate 			case 'e':
6387c478bd9Sstevel@tonic-gate 				casecnt = 0;
6397c478bd9Sstevel@tonic-gate 				continue;
6407c478bd9Sstevel@tonic-gate 			}
6417c478bd9Sstevel@tonic-gate 			if(re != NULL && c >= '1' && c < re->Nbra + '1') {
6427c478bd9Sstevel@tonic-gate 				sp = place(sp, braslist[c - '1'] , braelist[c - '1']);
6437c478bd9Sstevel@tonic-gate 				if (sp == 0)
6447c478bd9Sstevel@tonic-gate 					goto ovflo;
6457c478bd9Sstevel@tonic-gate 				continue;
6467c478bd9Sstevel@tonic-gate 			}
6477c478bd9Sstevel@tonic-gate 			rp--;
6487c478bd9Sstevel@tonic-gate 		}
6497c478bd9Sstevel@tonic-gate 		if (len > 1) {
6507c478bd9Sstevel@tonic-gate 			if ((sp + len) >= &genbuf[LBSIZE])
6517c478bd9Sstevel@tonic-gate 				goto ovflo;
6527c478bd9Sstevel@tonic-gate 			strncpy(sp, rp, len);
6537c478bd9Sstevel@tonic-gate 		} else {
6547c478bd9Sstevel@tonic-gate 			if (casecnt)
6557c478bd9Sstevel@tonic-gate 				*sp = fixcase(c);
6567c478bd9Sstevel@tonic-gate 			else
6577c478bd9Sstevel@tonic-gate 				*sp = c;
6587c478bd9Sstevel@tonic-gate 		}
6597c478bd9Sstevel@tonic-gate 		sp += len; rp += len;
6607c478bd9Sstevel@tonic-gate 		if (sp >= &genbuf[LBSIZE])
6617c478bd9Sstevel@tonic-gate ovflo:
6627c478bd9Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("Line overflow") :
6637c478bd9Sstevel@tonic-gate gettext("Line overflow in substitute"));
6647c478bd9Sstevel@tonic-gate 	}
6657c478bd9Sstevel@tonic-gate 	lp = (unsigned char *)loc2;
6667c478bd9Sstevel@tonic-gate 	loc2 = (char *)(linebuf + (sp - genbuf));
6677c478bd9Sstevel@tonic-gate 	while (*sp++ = *lp++)
6687c478bd9Sstevel@tonic-gate 		if (sp >= &genbuf[LBSIZE])
6697c478bd9Sstevel@tonic-gate 			goto ovflo;
6707c478bd9Sstevel@tonic-gate 	strcLIN(genbuf);
6717c478bd9Sstevel@tonic-gate }
6727c478bd9Sstevel@tonic-gate 
673f6db9f27Scf46844 int
fixcase(int c)674f6db9f27Scf46844 fixcase(int c)
6757c478bd9Sstevel@tonic-gate {
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 	if (casecnt == 0)
6787c478bd9Sstevel@tonic-gate 		return (c);
6797c478bd9Sstevel@tonic-gate 	casecnt--;
6807c478bd9Sstevel@tonic-gate 	if (destuc) {
6817c478bd9Sstevel@tonic-gate 		if (islower(c))
6827c478bd9Sstevel@tonic-gate 			c = toupper(c);
6837c478bd9Sstevel@tonic-gate 	} else
6847c478bd9Sstevel@tonic-gate 		if (isupper(c))
6857c478bd9Sstevel@tonic-gate 			c = tolower(c);
6867c478bd9Sstevel@tonic-gate 	return (c);
6877c478bd9Sstevel@tonic-gate }
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate unsigned char *
place(sp,l1,l2)6907c478bd9Sstevel@tonic-gate place(sp, l1, l2)
6917c478bd9Sstevel@tonic-gate 	unsigned char *sp, *l1, *l2;
6927c478bd9Sstevel@tonic-gate {
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	while (l1 < l2) {
6957c478bd9Sstevel@tonic-gate 		*sp++ = fixcase(*l1++);
6967c478bd9Sstevel@tonic-gate 		if (sp >= &genbuf[LBSIZE])
6977c478bd9Sstevel@tonic-gate 			return (0);
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate 	return (sp);
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate 
702f6db9f27Scf46844 void
snote(int total,int nlines)703f6db9f27Scf46844 snote(int total, int nlines)
7047c478bd9Sstevel@tonic-gate {
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	if (!notable(total))
7077c478bd9Sstevel@tonic-gate 		return;
7087c478bd9Sstevel@tonic-gate 	if (nlines != 1 && nlines != total)
709f6db9f27Scf46844 		viprintf(mesg(value(vi_TERSE) ?
7107c478bd9Sstevel@tonic-gate 			/*
7117c478bd9Sstevel@tonic-gate 			 * TRANSLATION_NOTE
7127c478bd9Sstevel@tonic-gate 			 *	Reference order of arguments must not
7137c478bd9Sstevel@tonic-gate 			 *	be changed using '%digit$', since vi's
714f6db9f27Scf46844 			 *	viprintf() does not support it.
7157c478bd9Sstevel@tonic-gate 			 */
7167c478bd9Sstevel@tonic-gate 			    gettext("%d subs on %d lines") :
7177c478bd9Sstevel@tonic-gate 			/*
7187c478bd9Sstevel@tonic-gate 			 * TRANSLATION_NOTE
7197c478bd9Sstevel@tonic-gate 			 *	Reference order of arguments must not
7207c478bd9Sstevel@tonic-gate 			 *	be changed using '%digit$', since vi's
721f6db9f27Scf46844 			 *	viprintf() does not support it.
7227c478bd9Sstevel@tonic-gate 			 */
7237c478bd9Sstevel@tonic-gate 			    gettext("%d substitutions on %d lines")),
7247c478bd9Sstevel@tonic-gate 		       total, nlines);
7257c478bd9Sstevel@tonic-gate 	else
726f6db9f27Scf46844 		viprintf(mesg(value(vi_TERSE) ?
7277c478bd9Sstevel@tonic-gate 			    gettext("%d subs") :
7287c478bd9Sstevel@tonic-gate 			    gettext("%d substitutions")),
7297c478bd9Sstevel@tonic-gate 		       total);
7307c478bd9Sstevel@tonic-gate 	noonl();
7317c478bd9Sstevel@tonic-gate 	flush();
7327c478bd9Sstevel@tonic-gate }
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate #ifdef XPG4
7357c478bd9Sstevel@tonic-gate #include <regex.h>
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate extern int regcomp_flags;	/* use to specify cflags for regcomp() */
7387c478bd9Sstevel@tonic-gate #endif /* XPG4 */
7397c478bd9Sstevel@tonic-gate 
740f6db9f27Scf46844 int
vi_compile(int eof,int oknl)741f6db9f27Scf46844 vi_compile(int eof, int oknl)
7427c478bd9Sstevel@tonic-gate {
7437c478bd9Sstevel@tonic-gate 	int c;
7447c478bd9Sstevel@tonic-gate 	unsigned char *gp, *p1;
7457c478bd9Sstevel@tonic-gate 	unsigned char *rhsp;
7467c478bd9Sstevel@tonic-gate 	unsigned char rebuf[LBSIZE];
7477c478bd9Sstevel@tonic-gate 	char	multi[MB_LEN_MAX + 1];
7487c478bd9Sstevel@tonic-gate 	int	len;
7497c478bd9Sstevel@tonic-gate 	wchar_t	wc;
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate #ifdef XPG4
7527c478bd9Sstevel@tonic-gate 	/*
7537c478bd9Sstevel@tonic-gate 	 * reset cflags to plain BRE
7547c478bd9Sstevel@tonic-gate 	 * if \< and/or \> is specified, REG_WORDS is set.
7557c478bd9Sstevel@tonic-gate 	 */
7567c478bd9Sstevel@tonic-gate 	regcomp_flags = 0;
7577c478bd9Sstevel@tonic-gate #endif /* XPG4 */
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	gp = genbuf;
7607c478bd9Sstevel@tonic-gate 	if (isalpha(eof) || isdigit(eof))
7617c478bd9Sstevel@tonic-gate error(gettext("Regular expressions cannot be delimited by letters or digits"));
7627c478bd9Sstevel@tonic-gate 	if(eof >= 0200 && MB_CUR_MAX > 1)
7637c478bd9Sstevel@tonic-gate error(gettext("Regular expressions cannot be delimited by multibyte characters"));
7647c478bd9Sstevel@tonic-gate 	c = getchar();
7657c478bd9Sstevel@tonic-gate 	if (eof == '\\')
7667c478bd9Sstevel@tonic-gate 		switch (c) {
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 		case '/':
7697c478bd9Sstevel@tonic-gate 		case '?':
7707c478bd9Sstevel@tonic-gate 			if (scanre == NULL || scanre->Expbuf[1] == 0)
7717c478bd9Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("No previous scan re") :
7727c478bd9Sstevel@tonic-gate gettext("No previous scanning regular expression"));
7737c478bd9Sstevel@tonic-gate 			resre(scanre);
7747c478bd9Sstevel@tonic-gate 			return (c);
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 		case '&':
7777c478bd9Sstevel@tonic-gate 			if (subre == NULL || subre->Expbuf[1] == 0)
7787c478bd9Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("No previous substitute re") :
7797c478bd9Sstevel@tonic-gate gettext("No previous substitute regular expression"));
7807c478bd9Sstevel@tonic-gate 			resre(subre);
7817c478bd9Sstevel@tonic-gate 			return (c);
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 		default:
7847c478bd9Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("Badly formed re") :
7857c478bd9Sstevel@tonic-gate gettext("Regular expression \\ must be followed by / or ?"));
7867c478bd9Sstevel@tonic-gate 		}
7877c478bd9Sstevel@tonic-gate 	if (c == eof || c == '\n' || c == EOF) {
7887c478bd9Sstevel@tonic-gate 		if (re == NULL || re->Expbuf[1] == 0)
7897c478bd9Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("No previous re") :
7907c478bd9Sstevel@tonic-gate gettext("No previous regular expression"));
7917c478bd9Sstevel@tonic-gate 		if (c == '\n' && oknl == 0)
7927c478bd9Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("Missing closing delimiter") :
7937c478bd9Sstevel@tonic-gate gettext("Missing closing delimiter for regular expression"));
7947c478bd9Sstevel@tonic-gate 		if (c != eof)
7957c478bd9Sstevel@tonic-gate 			ungetchar(c);
7967c478bd9Sstevel@tonic-gate 		return (eof);
7977c478bd9Sstevel@tonic-gate 	}
7987c478bd9Sstevel@tonic-gate 	gp = genbuf;
7997c478bd9Sstevel@tonic-gate 	if (c == '^') {
8007c478bd9Sstevel@tonic-gate 		*gp++ = c;
8017c478bd9Sstevel@tonic-gate 		c = getchar();
8027c478bd9Sstevel@tonic-gate 	}
8037c478bd9Sstevel@tonic-gate 	ungetchar(c);
8047c478bd9Sstevel@tonic-gate 	for (;;) {
8057c478bd9Sstevel@tonic-gate 		c = getchar();
8067c478bd9Sstevel@tonic-gate 		if (c == eof || c == EOF) {
8077c478bd9Sstevel@tonic-gate 			if (c == EOF)
8087c478bd9Sstevel@tonic-gate 				ungetchar(c);
8097c478bd9Sstevel@tonic-gate 			goto out;
8107c478bd9Sstevel@tonic-gate 		}
8117c478bd9Sstevel@tonic-gate 		if (gp >= &genbuf[LBSIZE - 3])
8127c478bd9Sstevel@tonic-gate complex:
813f6db9f27Scf46844 			cerror(value(vi_TERSE) ?
814f6db9f27Scf46844 			    (unsigned char *)gettext("Re too complex") :
815f6db9f27Scf46844 			    (unsigned char *)
8167c478bd9Sstevel@tonic-gate 			    gettext("Regular expression too complicated"));
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 		if (!(isascii(c) || MB_CUR_MAX == 1)) {
8197c478bd9Sstevel@tonic-gate 			ungetchar(c);
8207c478bd9Sstevel@tonic-gate 			if ((len = _mbftowc(multi, &wc, getchar, &peekc)) >= 1) {
8217c478bd9Sstevel@tonic-gate 				if ((gp + len) >= &genbuf[LBSIZE - 3])
8227c478bd9Sstevel@tonic-gate 					goto complex;
8237c478bd9Sstevel@tonic-gate 				strncpy(gp, multi, len);
8247c478bd9Sstevel@tonic-gate 				gp += len;
8257c478bd9Sstevel@tonic-gate 				continue;
8267c478bd9Sstevel@tonic-gate 			}
8277c478bd9Sstevel@tonic-gate 			(void) getchar();
8287c478bd9Sstevel@tonic-gate 		}
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 		switch (c) {
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 		case '\\':
8337c478bd9Sstevel@tonic-gate 			c = getchar();
8347c478bd9Sstevel@tonic-gate 			if (!isascii(c)) {
8357c478bd9Sstevel@tonic-gate 				ungetchar(c);
8367c478bd9Sstevel@tonic-gate 				if ((len = _mbftowc(multi, &wc, getchar, &peekc)) >= 1) {
8377c478bd9Sstevel@tonic-gate 					if ((gp + len) >= &genbuf[LBSIZE - 3])
8387c478bd9Sstevel@tonic-gate 						goto complex;
8397c478bd9Sstevel@tonic-gate 					*gp++ = '\\';
8407c478bd9Sstevel@tonic-gate 					strncpy(gp, multi, len);
8417c478bd9Sstevel@tonic-gate 					gp += len;
8427c478bd9Sstevel@tonic-gate 					continue;
8437c478bd9Sstevel@tonic-gate 				}
8447c478bd9Sstevel@tonic-gate 				(void) getchar();
8457c478bd9Sstevel@tonic-gate 			}
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 			switch (c) {
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 			case '<':
8507c478bd9Sstevel@tonic-gate 			case '>':
8517c478bd9Sstevel@tonic-gate #ifdef XPG4
8527c478bd9Sstevel@tonic-gate 				regcomp_flags = REG_WORDS;
8537c478bd9Sstevel@tonic-gate 				/*FALLTHRU*/
8547c478bd9Sstevel@tonic-gate #endif /* XPG4 */
8557c478bd9Sstevel@tonic-gate 			case '(':
8567c478bd9Sstevel@tonic-gate 			case ')':
8577c478bd9Sstevel@tonic-gate 			case '{':
8587c478bd9Sstevel@tonic-gate 			case '}':
8597c478bd9Sstevel@tonic-gate 			case '$':
8607c478bd9Sstevel@tonic-gate 			case '^':
8617c478bd9Sstevel@tonic-gate 			case '\\':
8627c478bd9Sstevel@tonic-gate 				*gp++ = '\\';
8637c478bd9Sstevel@tonic-gate 				*gp++ = c;
8647c478bd9Sstevel@tonic-gate 				continue;
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 			case 'n':
8677c478bd9Sstevel@tonic-gate 				*gp++ = c;
8687c478bd9Sstevel@tonic-gate 				continue;
8697c478bd9Sstevel@tonic-gate 			}
8707c478bd9Sstevel@tonic-gate 			if(c >= '0' && c <= '9') {
8717c478bd9Sstevel@tonic-gate 				*gp++ = '\\';
8727c478bd9Sstevel@tonic-gate 				*gp++ = c;
8737c478bd9Sstevel@tonic-gate 				continue;
8747c478bd9Sstevel@tonic-gate 			}
8757c478bd9Sstevel@tonic-gate 			if (value(vi_MAGIC) == 0)
8767c478bd9Sstevel@tonic-gate magic:
8777c478bd9Sstevel@tonic-gate 			switch (c) {
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 			case '.':
8807c478bd9Sstevel@tonic-gate 				*gp++ = '.';
8817c478bd9Sstevel@tonic-gate 				continue;
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 			case '~':
8847c478bd9Sstevel@tonic-gate 				rhsp = rhsbuf;
8857c478bd9Sstevel@tonic-gate 				while (*rhsp) {
8867c478bd9Sstevel@tonic-gate 					if (!isascii(*rhsp)) {
8877c478bd9Sstevel@tonic-gate 						if ((len = mbtowc((wchar_t *)0, (char *)rhsp, MB_CUR_MAX)) > 1) {
8887c478bd9Sstevel@tonic-gate 							if ((gp + len) >= &genbuf[LBSIZE-2])
8897c478bd9Sstevel@tonic-gate 								goto complex;
8907c478bd9Sstevel@tonic-gate 							strncpy(gp, rhsp, len);
8917c478bd9Sstevel@tonic-gate 							rhsp += len; gp += len;
8927c478bd9Sstevel@tonic-gate 							continue;
8937c478bd9Sstevel@tonic-gate 						}
8947c478bd9Sstevel@tonic-gate 					}
8957c478bd9Sstevel@tonic-gate 					len = 1;
8967c478bd9Sstevel@tonic-gate 					if (*rhsp == '\\') {
8977c478bd9Sstevel@tonic-gate 						c = *++rhsp;
8987c478bd9Sstevel@tonic-gate 						if (c == '&')
899f6db9f27Scf46844 cerror(value(vi_TERSE) ? (unsigned char *)
900f6db9f27Scf46844 gettext("Replacement pattern contains &") :
901f6db9f27Scf46844 (unsigned char *)gettext("Replacement pattern contains & - cannot use in re"));
9027c478bd9Sstevel@tonic-gate 						if (c >= '1' && c <= '9')
903f6db9f27Scf46844 cerror(value(vi_TERSE) ? (unsigned char *)
904f6db9f27Scf46844 gettext("Replacement pattern contains \\d") :
905f6db9f27Scf46844 (unsigned char *)
9067c478bd9Sstevel@tonic-gate gettext("Replacement pattern contains \\d - cannot use in re"));
9077c478bd9Sstevel@tonic-gate 						if ((len = mbtowc((wchar_t *)0, (char *)rhsp, MB_CUR_MAX)) <= 1) {
9087c478bd9Sstevel@tonic-gate 							len = 1;
9097c478bd9Sstevel@tonic-gate 							if(any(c, ".\\*[$"))
9107c478bd9Sstevel@tonic-gate 								*gp++ = '\\';
9117c478bd9Sstevel@tonic-gate 						}
9127c478bd9Sstevel@tonic-gate 					}
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 					if ((gp + len) >= &genbuf[LBSIZE-2])
9157c478bd9Sstevel@tonic-gate 						goto complex;
9167c478bd9Sstevel@tonic-gate 					if (len == 1) {
9177c478bd9Sstevel@tonic-gate 						c = *rhsp++;
9187c478bd9Sstevel@tonic-gate 						*gp++ = (value(vi_IGNORECASE) ? tolower(c) : c);
9197c478bd9Sstevel@tonic-gate 					} else {
9207c478bd9Sstevel@tonic-gate 						strncpy(gp, rhsp, len);
9217c478bd9Sstevel@tonic-gate 						gp += len; rhsp += len;
9227c478bd9Sstevel@tonic-gate 					}
9237c478bd9Sstevel@tonic-gate 				}
9247c478bd9Sstevel@tonic-gate 				continue;
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate 			case '*':
9277c478bd9Sstevel@tonic-gate 				*gp++ = '*';
9287c478bd9Sstevel@tonic-gate 				continue;
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 			case '[':
9317c478bd9Sstevel@tonic-gate 				*gp++ = '[';
9327c478bd9Sstevel@tonic-gate 				c = getchar();
9337c478bd9Sstevel@tonic-gate 				if (c == '^') {
9347c478bd9Sstevel@tonic-gate 					*gp++ = '^';
9357c478bd9Sstevel@tonic-gate 					c = getchar();
9367c478bd9Sstevel@tonic-gate 				}
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 				do {
9397c478bd9Sstevel@tonic-gate 					if (!isascii(c) && c != EOF) {
9407c478bd9Sstevel@tonic-gate 						ungetchar(c);
9417c478bd9Sstevel@tonic-gate 						if ((len = _mbftowc(multi, &wc, getchar, &peekc)) >= 1) {
9427c478bd9Sstevel@tonic-gate 							if ((gp + len)>= &genbuf[LBSIZE-4])
9437c478bd9Sstevel@tonic-gate 								goto complex;
9447c478bd9Sstevel@tonic-gate 							strncpy(gp, multi, len);
9457c478bd9Sstevel@tonic-gate 							gp += len;
9467c478bd9Sstevel@tonic-gate 							c = getchar();
9477c478bd9Sstevel@tonic-gate 							continue;
9487c478bd9Sstevel@tonic-gate 						}
9497c478bd9Sstevel@tonic-gate 						(void) getchar();
9507c478bd9Sstevel@tonic-gate 					}
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 					if (gp >= &genbuf[LBSIZE-4])
9537c478bd9Sstevel@tonic-gate 						goto complex;
9547c478bd9Sstevel@tonic-gate 					if(c == '\\' && peekchar() == ']') {
9557c478bd9Sstevel@tonic-gate 						(void)getchar();
9567c478bd9Sstevel@tonic-gate 						*gp++ = '\\';
9577c478bd9Sstevel@tonic-gate 						*gp++ = ']';
9587c478bd9Sstevel@tonic-gate 					}
9597c478bd9Sstevel@tonic-gate 					else if (c == '\n' || c == EOF)
960f6db9f27Scf46844 						cerror((unsigned char *)
961f6db9f27Scf46844 						    gettext("Missing ]"));
9627c478bd9Sstevel@tonic-gate 					else
9637c478bd9Sstevel@tonic-gate 						*gp++ = (value(vi_IGNORECASE) ? tolower(c) : c);
9647c478bd9Sstevel@tonic-gate 					c = getchar();
9657c478bd9Sstevel@tonic-gate 				} while(c != ']');
9667c478bd9Sstevel@tonic-gate 				*gp++ = ']';
9677c478bd9Sstevel@tonic-gate 				continue;
9687c478bd9Sstevel@tonic-gate 			}
9697c478bd9Sstevel@tonic-gate 			if (c == EOF) {
9707c478bd9Sstevel@tonic-gate 				ungetchar(EOF);
9717c478bd9Sstevel@tonic-gate 				*gp++ = '\\';
9727c478bd9Sstevel@tonic-gate 				*gp++ = '\\';
9737c478bd9Sstevel@tonic-gate 				continue;
9747c478bd9Sstevel@tonic-gate 			}
9757c478bd9Sstevel@tonic-gate 			if (c == '\n')
976f6db9f27Scf46844 cerror(value(vi_TERSE) ? (unsigned char *)gettext("No newlines in re's") :
977f6db9f27Scf46844 (unsigned char *)gettext("Can't escape newlines into regular expressions"));
9787c478bd9Sstevel@tonic-gate 			*gp++ = '\\';
9797c478bd9Sstevel@tonic-gate 			*gp++ = (value(vi_IGNORECASE) ? tolower(c) : c);
9807c478bd9Sstevel@tonic-gate 			continue;
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 		case '\n':
9837c478bd9Sstevel@tonic-gate 			if (oknl) {
9847c478bd9Sstevel@tonic-gate 				ungetchar(c);
9857c478bd9Sstevel@tonic-gate 				goto out;
9867c478bd9Sstevel@tonic-gate 			}
987f6db9f27Scf46844 cerror(value(vi_TERSE) ? (unsigned char *)gettext("Badly formed re") :
988f6db9f27Scf46844 (unsigned char *)gettext("Missing closing delimiter for regular expression"));
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 		case '.':
9917c478bd9Sstevel@tonic-gate 		case '~':
9927c478bd9Sstevel@tonic-gate 		case '*':
9937c478bd9Sstevel@tonic-gate 		case '[':
9947c478bd9Sstevel@tonic-gate 			if (value(vi_MAGIC))
9957c478bd9Sstevel@tonic-gate 				goto magic;
9967c478bd9Sstevel@tonic-gate 			if(c != '~')
9977c478bd9Sstevel@tonic-gate 				*gp++ = '\\';
9987c478bd9Sstevel@tonic-gate defchar:
9997c478bd9Sstevel@tonic-gate 		default:
10007c478bd9Sstevel@tonic-gate 			*gp++ = (value(vi_IGNORECASE) ? tolower(c) : c);
10017c478bd9Sstevel@tonic-gate 			continue;
10027c478bd9Sstevel@tonic-gate 		}
10037c478bd9Sstevel@tonic-gate 	}
10047c478bd9Sstevel@tonic-gate out:
10057c478bd9Sstevel@tonic-gate 	*gp++ = '\0';
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate #ifdef XPG4
10087c478bd9Sstevel@tonic-gate 	/* see if our compiled RE's will fit in the re structure:	*/
10097c478bd9Sstevel@tonic-gate 	if (regexc_size > EXPSIZ) {
10107c478bd9Sstevel@tonic-gate 		/*
10117c478bd9Sstevel@tonic-gate 		 * this should never happen. but it's critical that we
10127c478bd9Sstevel@tonic-gate 		 * check here, otherwise .bss would get overwritten.
10137c478bd9Sstevel@tonic-gate 		 */
1014f6db9f27Scf46844 		cerror(value(vi_TERSE) ? (unsigned char *)
1015f6db9f27Scf46844 		    gettext("RE's can't fit") :
1016f6db9f27Scf46844 		    (unsigned char *)gettext("Regular expressions can't fit"));
10177c478bd9Sstevel@tonic-gate 		return(eof);
10187c478bd9Sstevel@tonic-gate 	}
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	/*
10217c478bd9Sstevel@tonic-gate 	 * We create re each time we need it.
10227c478bd9Sstevel@tonic-gate 	 */
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	if (re == NULL || re == scanre || re == subre) {
10257c478bd9Sstevel@tonic-gate 		if ((re = calloc(1, sizeof(struct regexp))) == NULL) {
10267c478bd9Sstevel@tonic-gate 			error(gettext("out of memory"));
10277c478bd9Sstevel@tonic-gate 			exit(errcnt);
10287c478bd9Sstevel@tonic-gate 		}
10297c478bd9Sstevel@tonic-gate 	} else {
10307c478bd9Sstevel@tonic-gate 		regex_comp_free(&re->Expbuf);
10317c478bd9Sstevel@tonic-gate 		memset(re, 0, sizeof(struct regexp));
10327c478bd9Sstevel@tonic-gate 	}
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 	compile((char *) genbuf, (char *) re->Expbuf, (char *) re->Expbuf
10357c478bd9Sstevel@tonic-gate 	    + regexc_size);
10367c478bd9Sstevel@tonic-gate #else /* !XPG4 */
10377c478bd9Sstevel@tonic-gate 	(void) _compile((const char *)genbuf, (char *)re->Expbuf,
10387c478bd9Sstevel@tonic-gate 		(char *)(re->Expbuf + sizeof (re->Expbuf)), 1);
10397c478bd9Sstevel@tonic-gate #endif /* XPG4 */
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	if(regerrno)
10427c478bd9Sstevel@tonic-gate 		switch(regerrno) {
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 		case 42:
1045f6db9f27Scf46844 cerror((unsigned char *)gettext("\\( \\) Imbalance"));
10467c478bd9Sstevel@tonic-gate 		case 43:
1047f6db9f27Scf46844 cerror(value(vi_TERSE) ? (unsigned char *)gettext("Awash in \\('s!") :
1048f6db9f27Scf46844 (unsigned char *)
10497c478bd9Sstevel@tonic-gate gettext("Too many \\('d subexpressions in a regular expression"));
10507c478bd9Sstevel@tonic-gate 		case 50:
10517c478bd9Sstevel@tonic-gate 			goto complex;
10527c478bd9Sstevel@tonic-gate 		case 67:
1053f6db9f27Scf46844 cerror(value(vi_TERSE) ? (unsigned char *)gettext("Illegal byte sequence") :
1054f6db9f27Scf46844 (unsigned char *)gettext("Regular expression has illegal byte sequence"));
10557c478bd9Sstevel@tonic-gate 		}
10567c478bd9Sstevel@tonic-gate 	re->Nbra = nbra;
10577c478bd9Sstevel@tonic-gate 	return(eof);
10587c478bd9Sstevel@tonic-gate }
10597c478bd9Sstevel@tonic-gate 
1060f6db9f27Scf46844 void
cerror(unsigned char * s)1061f6db9f27Scf46844 cerror(unsigned char *s)
10627c478bd9Sstevel@tonic-gate {
10637c478bd9Sstevel@tonic-gate 	if (re) {
10647c478bd9Sstevel@tonic-gate 		re->Expbuf[0] = re->Expbuf[1] = 0;
10657c478bd9Sstevel@tonic-gate 	}
10667c478bd9Sstevel@tonic-gate 	error(s);
10677c478bd9Sstevel@tonic-gate }
10687c478bd9Sstevel@tonic-gate 
1069f6db9f27Scf46844 int
execute(int gf,line * addr)1070f6db9f27Scf46844 execute(int gf, line *addr)
10717c478bd9Sstevel@tonic-gate {
10727c478bd9Sstevel@tonic-gate 	unsigned char *p1, *p2;
10737c478bd9Sstevel@tonic-gate 	char *start;
10747c478bd9Sstevel@tonic-gate 	int c, i;
10757c478bd9Sstevel@tonic-gate 	int ret;
10767c478bd9Sstevel@tonic-gate 	int	len;
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate 	if (gf) {
10797c478bd9Sstevel@tonic-gate 		if (re == NULL || re->Expbuf[0])
10807c478bd9Sstevel@tonic-gate 			return (0);
10817c478bd9Sstevel@tonic-gate 		if(value(vi_IGNORECASE)) {
10827c478bd9Sstevel@tonic-gate 			p1 = genbuf;
10837c478bd9Sstevel@tonic-gate 			p2 = (unsigned char *)loc2;
10847c478bd9Sstevel@tonic-gate 			while(c = *p2) {
10857c478bd9Sstevel@tonic-gate 				if ((len = mblen((char *)p2, MB_CUR_MAX)) <= 0)
10867c478bd9Sstevel@tonic-gate 					len = 1;
10877c478bd9Sstevel@tonic-gate 				if (len == 1) {
10887c478bd9Sstevel@tonic-gate 					*p1++ = tolower(c);
10897c478bd9Sstevel@tonic-gate 					p2++;
10907c478bd9Sstevel@tonic-gate 					continue;
10917c478bd9Sstevel@tonic-gate 				}
10927c478bd9Sstevel@tonic-gate 				strncpy(p1, p2, len);
10937c478bd9Sstevel@tonic-gate 				p1 += len; p2 += len;
10947c478bd9Sstevel@tonic-gate 			}
10957c478bd9Sstevel@tonic-gate 			*p1 = '\0';
10967c478bd9Sstevel@tonic-gate 			locs = (char *)genbuf;
10977c478bd9Sstevel@tonic-gate 			p1 = genbuf;
10987c478bd9Sstevel@tonic-gate 			start = loc2;
10997c478bd9Sstevel@tonic-gate 		} else {
11007c478bd9Sstevel@tonic-gate 			p1 = (unsigned char *)loc2;
11017c478bd9Sstevel@tonic-gate 			locs = loc2;
11027c478bd9Sstevel@tonic-gate 		}
11037c478bd9Sstevel@tonic-gate 	} else {
11047c478bd9Sstevel@tonic-gate 		if (addr == zero)
11057c478bd9Sstevel@tonic-gate 			return (0);
11067c478bd9Sstevel@tonic-gate 		p1 = linebuf;
1107*23a1cceaSRoger A. Faulkner 		getaline(*addr);
11087c478bd9Sstevel@tonic-gate 		if(value(vi_IGNORECASE)) {
11097c478bd9Sstevel@tonic-gate 			p1 = genbuf;
11107c478bd9Sstevel@tonic-gate 			p2 = linebuf;
11117c478bd9Sstevel@tonic-gate 			while(c = *p2) {
11127c478bd9Sstevel@tonic-gate 				if ((len = mblen((char *)p2, MB_CUR_MAX)) <= 0)
11137c478bd9Sstevel@tonic-gate 					len = 1;
11147c478bd9Sstevel@tonic-gate 				if (len == 1) {
11157c478bd9Sstevel@tonic-gate 					*p1++ = tolower(c);
11167c478bd9Sstevel@tonic-gate 					p2++;
11177c478bd9Sstevel@tonic-gate 					continue;
11187c478bd9Sstevel@tonic-gate 				}
11197c478bd9Sstevel@tonic-gate 				strncpy(p1, p2, len);
11207c478bd9Sstevel@tonic-gate 				p1 += len; p2 += len;
11217c478bd9Sstevel@tonic-gate 			}
11227c478bd9Sstevel@tonic-gate 			*p1 = '\0';
11237c478bd9Sstevel@tonic-gate 			p1 = genbuf;
11247c478bd9Sstevel@tonic-gate 			start = (char *)linebuf;
11257c478bd9Sstevel@tonic-gate 		}
11267c478bd9Sstevel@tonic-gate 		locs = (char *)0;
11277c478bd9Sstevel@tonic-gate 	}
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	ret = step((char *)p1, (char *)re->Expbuf);
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	if(value(vi_IGNORECASE) && ret) {
11327c478bd9Sstevel@tonic-gate 		loc1 = start + (loc1 - (char *)genbuf);
11337c478bd9Sstevel@tonic-gate 		loc2 = start + (loc2 - (char *)genbuf);
11347c478bd9Sstevel@tonic-gate 		for(i = 0; i < NBRA; i++) {
11357c478bd9Sstevel@tonic-gate 			braslist[i] = start + (braslist[i] - (char *)genbuf);
11367c478bd9Sstevel@tonic-gate 			braelist[i] = start + (braelist[i] - (char *)genbuf);
11377c478bd9Sstevel@tonic-gate 		}
11387c478bd9Sstevel@tonic-gate 	}
11397c478bd9Sstevel@tonic-gate 	return ret;
11407c478bd9Sstevel@tonic-gate }
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate /*
11437c478bd9Sstevel@tonic-gate  *  Initialize the compiled regular-expression storage areas (called from
11447c478bd9Sstevel@tonic-gate  *  main()).
11457c478bd9Sstevel@tonic-gate  */
11467c478bd9Sstevel@tonic-gate 
init_re(void)11477c478bd9Sstevel@tonic-gate void init_re (void)
11487c478bd9Sstevel@tonic-gate {
11497c478bd9Sstevel@tonic-gate #ifdef XPG4
11507c478bd9Sstevel@tonic-gate 	re = scanre = subre = NULL;
11517c478bd9Sstevel@tonic-gate #else /* !XPG4 */
11527c478bd9Sstevel@tonic-gate 	if ((re = calloc(1, sizeof(struct regexp))) == NULL) {
11537c478bd9Sstevel@tonic-gate 		error(gettext("out of memory"));
11547c478bd9Sstevel@tonic-gate 		exit(errcnt);
11557c478bd9Sstevel@tonic-gate 	}
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	if ((scanre = calloc(1, sizeof(struct regexp))) == NULL) {
11587c478bd9Sstevel@tonic-gate 		error(gettext("out of memory"));
11597c478bd9Sstevel@tonic-gate 		exit(errcnt);
11607c478bd9Sstevel@tonic-gate 	}
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 	if ((subre = calloc(1, sizeof(struct regexp))) == NULL) {
11637c478bd9Sstevel@tonic-gate 		error(gettext("out of memory"));
11647c478bd9Sstevel@tonic-gate 		exit(errcnt);
11657c478bd9Sstevel@tonic-gate 	}
11667c478bd9Sstevel@tonic-gate #endif /* XPG4 */
11677c478bd9Sstevel@tonic-gate }
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate /*
11707c478bd9Sstevel@tonic-gate  *  Save what is in the special place re to the named alternate
11717c478bd9Sstevel@tonic-gate  *  location.  This means freeing up what's currently in this target
11727c478bd9Sstevel@tonic-gate  *  location, if necessary.
11737c478bd9Sstevel@tonic-gate  */
11747c478bd9Sstevel@tonic-gate 
savere(struct regexp ** a)11757c478bd9Sstevel@tonic-gate void savere(struct regexp ** a)
11767c478bd9Sstevel@tonic-gate {
11777c478bd9Sstevel@tonic-gate #ifdef XPG4
11787c478bd9Sstevel@tonic-gate 	if (a == NULL || re == NULL) {
11797c478bd9Sstevel@tonic-gate 		return;
11807c478bd9Sstevel@tonic-gate 	}
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	if (*a == NULL) {
11837c478bd9Sstevel@tonic-gate 		*a = re;
11847c478bd9Sstevel@tonic-gate 		return;
11857c478bd9Sstevel@tonic-gate 	}
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 	if (*a != re) {
11887c478bd9Sstevel@tonic-gate 		if (scanre != subre) {
11897c478bd9Sstevel@tonic-gate 			regex_comp_free(&((*a)->Expbuf));
11907c478bd9Sstevel@tonic-gate 			free(*a);
11917c478bd9Sstevel@tonic-gate 		}
11927c478bd9Sstevel@tonic-gate 		*a = re;
11937c478bd9Sstevel@tonic-gate 	}
11947c478bd9Sstevel@tonic-gate #else /* !XPG4 */
11957c478bd9Sstevel@tonic-gate 	memcpy(*a, re, sizeof(struct regexp));
11967c478bd9Sstevel@tonic-gate #endif /* XPG4 */
11977c478bd9Sstevel@tonic-gate }
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate /*
12017c478bd9Sstevel@tonic-gate  *  Restore what is in the named alternate location to the special place
12027c478bd9Sstevel@tonic-gate  *  re.  This means first freeing up what's currently in re, if necessary.
12037c478bd9Sstevel@tonic-gate  */
12047c478bd9Sstevel@tonic-gate 
resre(struct regexp * a)12057c478bd9Sstevel@tonic-gate void resre(struct regexp * a)
12067c478bd9Sstevel@tonic-gate {
12077c478bd9Sstevel@tonic-gate #ifdef XPG4
12087c478bd9Sstevel@tonic-gate 	if (a == NULL) {
12097c478bd9Sstevel@tonic-gate 		return;
12107c478bd9Sstevel@tonic-gate 	}
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 	if (re == NULL) {
12137c478bd9Sstevel@tonic-gate 		re = a;
12147c478bd9Sstevel@tonic-gate 		return;
12157c478bd9Sstevel@tonic-gate 	}
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 	if (a != re) {
12187c478bd9Sstevel@tonic-gate 		if ((re != scanre) && (re != subre)) {
12197c478bd9Sstevel@tonic-gate 			regex_comp_free(&re->Expbuf);
12207c478bd9Sstevel@tonic-gate 			free(re);
12217c478bd9Sstevel@tonic-gate 		}
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 		re = a;
12247c478bd9Sstevel@tonic-gate 	}
12257c478bd9Sstevel@tonic-gate #else /* !XPG4 */
12267c478bd9Sstevel@tonic-gate 	memcpy(re, a, sizeof(struct regexp));
12277c478bd9Sstevel@tonic-gate #endif /* XPG4 */
12287c478bd9Sstevel@tonic-gate }
1229