xref: /onnv-gate/usr/src/cmd/vi/port/ex_re.c (revision 802:73b56fb6544b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
22*802Scf46844 /*
23*802Scf46844  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*802Scf46844  * Use is subject to license terms.
25*802Scf46844  */
26*802Scf46844 
270Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate 
310Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */
320Sstevel@tonic-gate 
33*802Scf46844 #pragma ident	"%Z%%M%	%I%	%E% SMI"
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include "ex.h"
360Sstevel@tonic-gate #include "ex_re.h"
370Sstevel@tonic-gate 
380Sstevel@tonic-gate /* from libgen */
390Sstevel@tonic-gate char *_compile(const char *, char *, char *, int);
400Sstevel@tonic-gate 
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate  * The compiled-regular-expression storage areas (re, scanre, and subre)
430Sstevel@tonic-gate  * have been changed into dynamically allocated memory areas, in both the
440Sstevel@tonic-gate  * Solaris and XPG4 versions.
450Sstevel@tonic-gate  *
460Sstevel@tonic-gate  * In the Solaris version, which uses the original libgen(3g) compile()
470Sstevel@tonic-gate  * and step() calls, these areas are allocated once, and then data are
480Sstevel@tonic-gate  * copied between them subsequently, as they were in the original
490Sstevel@tonic-gate  * implementation.  This is possible because the compiled information is
500Sstevel@tonic-gate  * a self-contained block of bits.
510Sstevel@tonic-gate  *
520Sstevel@tonic-gate  * In the XPG4 version, the expr:compile.o object is linked in as a
530Sstevel@tonic-gate  * simulation of these functions using the new regcomp() and regexec()
540Sstevel@tonic-gate  * functions.  The problem here is that the resulting
550Sstevel@tonic-gate  * compiled-regular-expression data contain pointers to other data, which
560Sstevel@tonic-gate  * need to be freed, but only when we are quite sure that we are done
570Sstevel@tonic-gate  * with them - and certainly not before.  There was an earlier attempt to
580Sstevel@tonic-gate  * handle these differences, but that effort was flawed.
590Sstevel@tonic-gate  */
600Sstevel@tonic-gate 
61*802Scf46844 extern int	getchar();
620Sstevel@tonic-gate #ifdef XPG4
630Sstevel@tonic-gate void regex_comp_free(void *);
640Sstevel@tonic-gate extern size_t regexc_size;	/* compile.c: size of regex_comp structure */
650Sstevel@tonic-gate #endif /* XPG4 */
660Sstevel@tonic-gate 
670Sstevel@tonic-gate /*
680Sstevel@tonic-gate  * Global, substitute and regular expressions.
690Sstevel@tonic-gate  * Very similar to ed, with some re extensions and
700Sstevel@tonic-gate  * confirmed substitute.
710Sstevel@tonic-gate  */
72*802Scf46844 void
730Sstevel@tonic-gate global(k)
740Sstevel@tonic-gate 	bool k;
750Sstevel@tonic-gate {
760Sstevel@tonic-gate 	unsigned char *gp;
770Sstevel@tonic-gate 	int c;
780Sstevel@tonic-gate 	line *a1;
790Sstevel@tonic-gate 	unsigned char globuf[GBSIZE], *Cwas;
800Sstevel@tonic-gate 	int nlines = lineDOL();
810Sstevel@tonic-gate 	int oinglobal = inglobal;
820Sstevel@tonic-gate 	unsigned char *oglobp = globp;
830Sstevel@tonic-gate 	char	multi[MB_LEN_MAX + 1];
840Sstevel@tonic-gate 	wchar_t	wc;
850Sstevel@tonic-gate 	int	len;
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	Cwas = Command;
890Sstevel@tonic-gate 	/*
900Sstevel@tonic-gate 	 * States of inglobal:
910Sstevel@tonic-gate 	 *  0: ordinary - not in a global command.
920Sstevel@tonic-gate 	 *  1: text coming from some buffer, not tty.
930Sstevel@tonic-gate 	 *  2: like 1, but the source of the buffer is a global command.
940Sstevel@tonic-gate 	 * Hence you're only in a global command if inglobal==2. This
950Sstevel@tonic-gate 	 * strange sounding convention is historically derived from
960Sstevel@tonic-gate 	 * everybody simulating a global command.
970Sstevel@tonic-gate 	 */
980Sstevel@tonic-gate 	if (inglobal==2)
990Sstevel@tonic-gate 		error(value(vi_TERSE) ? gettext("Global within global") :
1000Sstevel@tonic-gate gettext("Global within global not allowed"));
1010Sstevel@tonic-gate 	markDOT();
1020Sstevel@tonic-gate 	setall();
1030Sstevel@tonic-gate 	nonzero();
1040Sstevel@tonic-gate 	if (skipend())
1050Sstevel@tonic-gate 		error(value(vi_TERSE) ? gettext("Global needs re") :
1060Sstevel@tonic-gate gettext("Missing regular expression for global"));
1070Sstevel@tonic-gate 	c = getchar();
1080Sstevel@tonic-gate 	(void)vi_compile(c, 1);
1090Sstevel@tonic-gate 	savere(&scanre);
1100Sstevel@tonic-gate 	gp = globuf;
1110Sstevel@tonic-gate 	while ((c = peekchar()) != '\n') {
1120Sstevel@tonic-gate 		if (!isascii(c)) {
1130Sstevel@tonic-gate 			if (c == EOF) {
1140Sstevel@tonic-gate 				c = '\n';
1150Sstevel@tonic-gate 				ungetchar(c);
1160Sstevel@tonic-gate 				goto out;
1170Sstevel@tonic-gate 			}
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate mb_copy:
1200Sstevel@tonic-gate 			if ((len = _mbftowc(multi, &wc, getchar, &peekc)) > 0) {
1210Sstevel@tonic-gate 				if ((gp + len) >= &globuf[GBSIZE - 2])
1220Sstevel@tonic-gate 					error(gettext("Global command too long"));
1230Sstevel@tonic-gate 				strncpy(gp, multi, len);
1240Sstevel@tonic-gate 				gp += len;
1250Sstevel@tonic-gate 				continue;
1260Sstevel@tonic-gate 			}
1270Sstevel@tonic-gate 		}
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 		(void) getchar();
1300Sstevel@tonic-gate 		switch (c) {
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate 		case EOF:
1330Sstevel@tonic-gate 			c = '\n';
1340Sstevel@tonic-gate 			ungetchar(c);
1350Sstevel@tonic-gate 			goto out;
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 		case '\\':
1380Sstevel@tonic-gate 			c = peekchar();
1390Sstevel@tonic-gate 			if (!isascii(c)) {
1400Sstevel@tonic-gate 				*gp++ = '\\';
1410Sstevel@tonic-gate 				goto mb_copy;
1420Sstevel@tonic-gate 			}
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 			(void) getchar();
1450Sstevel@tonic-gate 			switch (c) {
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 			case '\\':
1480Sstevel@tonic-gate 				ungetchar(c);
1490Sstevel@tonic-gate 				break;
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 			case '\n':
1520Sstevel@tonic-gate 				break;
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 			default:
1550Sstevel@tonic-gate 				*gp++ = '\\';
1560Sstevel@tonic-gate 				break;
1570Sstevel@tonic-gate 			}
1580Sstevel@tonic-gate 			break;
1590Sstevel@tonic-gate 		}
1600Sstevel@tonic-gate 		*gp++ = c;
1610Sstevel@tonic-gate 		if (gp >= &globuf[GBSIZE - 2])
1620Sstevel@tonic-gate 			error(gettext("Global command too long"));
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate out:
1660Sstevel@tonic-gate 	donewline();
1670Sstevel@tonic-gate 	*gp++ = c;
1680Sstevel@tonic-gate 	*gp++ = 0;
1690Sstevel@tonic-gate 	saveall();
1700Sstevel@tonic-gate 	inglobal = 2;
1710Sstevel@tonic-gate 	for (a1 = one; a1 <= dol; a1++) {
1720Sstevel@tonic-gate 		*a1 &= ~01;
1730Sstevel@tonic-gate 		if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k)
1740Sstevel@tonic-gate 			*a1 |= 01;
1750Sstevel@tonic-gate 	}
1760Sstevel@tonic-gate #ifdef notdef
1770Sstevel@tonic-gate /*
1780Sstevel@tonic-gate  * This code is commented out for now.  The problem is that we don't
1790Sstevel@tonic-gate  * fix up the undo area the way we should.  Basically, I think what has
1800Sstevel@tonic-gate  * to be done is to copy the undo area down (since we shrunk everything)
1810Sstevel@tonic-gate  * and move the various pointers into it down too.  I will do this later
1820Sstevel@tonic-gate  * when I have time. (Mark, 10-20-80)
1830Sstevel@tonic-gate  */
1840Sstevel@tonic-gate 	/*
1850Sstevel@tonic-gate 	 * Special case: g/.../d (avoid n^2 algorithm)
1860Sstevel@tonic-gate 	 */
1870Sstevel@tonic-gate 	if (globuf[0]=='d' && globuf[1]=='\n' && globuf[2]=='\0') {
1880Sstevel@tonic-gate 		gdelete();
1890Sstevel@tonic-gate 		return;
1900Sstevel@tonic-gate 	}
1910Sstevel@tonic-gate #endif
1920Sstevel@tonic-gate 	if (inopen)
1930Sstevel@tonic-gate 		inopen = -1;
1940Sstevel@tonic-gate 	/*
1950Sstevel@tonic-gate 	 * Now for each marked line, set dot there and do the commands.
1960Sstevel@tonic-gate 	 * Note the n^2 behavior here for lots of lines matching.
1970Sstevel@tonic-gate 	 * This is really needed: in some cases you could delete lines,
1980Sstevel@tonic-gate 	 * causing a marked line to be moved before a1 and missed if
1990Sstevel@tonic-gate 	 * we didn't restart at zero each time.
2000Sstevel@tonic-gate 	 */
2010Sstevel@tonic-gate 	for (a1 = one; a1 <= dol; a1++) {
2020Sstevel@tonic-gate 		if (*a1 & 01) {
2030Sstevel@tonic-gate 			*a1 &= ~01;
2040Sstevel@tonic-gate 			dot = a1;
2050Sstevel@tonic-gate 			globp = globuf;
2060Sstevel@tonic-gate 			commands(1, 1);
2070Sstevel@tonic-gate 			a1 = zero;
2080Sstevel@tonic-gate 		}
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate 	globp = oglobp;
2110Sstevel@tonic-gate 	inglobal = oinglobal;
2120Sstevel@tonic-gate 	endline = 1;
2130Sstevel@tonic-gate 	Command = Cwas;
2140Sstevel@tonic-gate 	netchHAD(nlines);
2150Sstevel@tonic-gate 	setlastchar(EOF);
2160Sstevel@tonic-gate 	if (inopen) {
2170Sstevel@tonic-gate 		ungetchar(EOF);
2180Sstevel@tonic-gate 		inopen = 1;
2190Sstevel@tonic-gate 	}
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate /*
2230Sstevel@tonic-gate  * gdelete: delete inside a global command. Handles the
2240Sstevel@tonic-gate  * special case g/r.e./d. All lines to be deleted have
2250Sstevel@tonic-gate  * already been marked. Squeeze the remaining lines together.
2260Sstevel@tonic-gate  * Note that other cases such as g/r.e./p, g/r.e./s/r.e.2/rhs/,
2270Sstevel@tonic-gate  * and g/r.e./.,/r.e.2/d are not treated specially.  There is no
2280Sstevel@tonic-gate  * good reason for this except the question: where to you draw the line?
2290Sstevel@tonic-gate  */
230*802Scf46844 void
231*802Scf46844 gdelete(void)
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate 	line *a1, *a2, *a3;
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	a3 = dol;
2360Sstevel@tonic-gate 	/* find first marked line. can skip all before it */
2370Sstevel@tonic-gate 	for (a1=zero; (*a1&01)==0; a1++)
2380Sstevel@tonic-gate 		if (a1>=a3)
2390Sstevel@tonic-gate 			return;
2400Sstevel@tonic-gate 	/* copy down unmarked lines, compacting as we go. */
2410Sstevel@tonic-gate 	for (a2=a1+1; a2<=a3;) {
2420Sstevel@tonic-gate 		if (*a2&01) {
2430Sstevel@tonic-gate 			a2++;		/* line is marked, skip it */
2440Sstevel@tonic-gate 			dot = a1;	/* dot left after line deletion */
2450Sstevel@tonic-gate 		} else
2460Sstevel@tonic-gate 			*a1++ = *a2++;	/* unmarked, copy it */
2470Sstevel@tonic-gate 	}
2480Sstevel@tonic-gate 	dol = a1-1;
2490Sstevel@tonic-gate 	if (dot>dol)
2500Sstevel@tonic-gate 		dot = dol;
2510Sstevel@tonic-gate 	change();
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate bool	cflag;
2550Sstevel@tonic-gate int	scount, slines, stotal;
2560Sstevel@tonic-gate 
257*802Scf46844 int
258*802Scf46844 substitute(int c)
2590Sstevel@tonic-gate {
2600Sstevel@tonic-gate 	line *addr;
2610Sstevel@tonic-gate 	int n;
2620Sstevel@tonic-gate 	int gsubf, hopcount;
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	gsubf = compsub(c);
2650Sstevel@tonic-gate 	if(FIXUNDO)
2660Sstevel@tonic-gate 		save12(), undkind = UNDCHANGE;
2670Sstevel@tonic-gate 	stotal = 0;
2680Sstevel@tonic-gate 	slines = 0;
2690Sstevel@tonic-gate 	for (addr = addr1; addr <= addr2; addr++) {
2700Sstevel@tonic-gate 		scount = hopcount = 0;
2710Sstevel@tonic-gate 		if (dosubcon(0, addr) == 0)
2720Sstevel@tonic-gate 			continue;
2730Sstevel@tonic-gate 		if (gsubf) {
2740Sstevel@tonic-gate 			/*
2750Sstevel@tonic-gate 			 * The loop can happen from s/\</&/g
2760Sstevel@tonic-gate 			 * but we don't want to break other, reasonable cases.
2770Sstevel@tonic-gate 			 */
2780Sstevel@tonic-gate 			hopcount = 0;
2790Sstevel@tonic-gate 			while (*loc2) {
2800Sstevel@tonic-gate 				if (++hopcount > sizeof linebuf)
2810Sstevel@tonic-gate 					error(gettext("substitution loop"));
2820Sstevel@tonic-gate 				if (dosubcon(1, addr) == 0)
2830Sstevel@tonic-gate 					break;
2840Sstevel@tonic-gate 			}
2850Sstevel@tonic-gate 		}
2860Sstevel@tonic-gate 		if (scount) {
2870Sstevel@tonic-gate 			stotal += scount;
2880Sstevel@tonic-gate 			slines++;
2890Sstevel@tonic-gate 			putmark(addr);
2900Sstevel@tonic-gate 			n = append(getsub, addr);
2910Sstevel@tonic-gate 			addr += n;
2920Sstevel@tonic-gate 			addr2 += n;
2930Sstevel@tonic-gate 		}
2940Sstevel@tonic-gate 	}
2950Sstevel@tonic-gate 	if (stotal == 0 && !inglobal && !cflag)
2960Sstevel@tonic-gate 		error(value(vi_TERSE) ? gettext("Fail") :
2970Sstevel@tonic-gate gettext("Substitute pattern match failed"));
2980Sstevel@tonic-gate 	snote(stotal, slines);
2990Sstevel@tonic-gate 	return (stotal);
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate 
302*802Scf46844 int
303*802Scf46844 compsub(int ch)
3040Sstevel@tonic-gate {
3050Sstevel@tonic-gate 	int seof, c, uselastre;
3060Sstevel@tonic-gate 	static int gsubf;
3070Sstevel@tonic-gate 	static unsigned char remem[RHSSIZE];
3080Sstevel@tonic-gate 	static int remflg = -1;
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	if (!value(vi_EDCOMPATIBLE))
3110Sstevel@tonic-gate 		gsubf = cflag = 0;
3120Sstevel@tonic-gate 	uselastre = 0;
3130Sstevel@tonic-gate 	switch (ch) {
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	case 's':
3160Sstevel@tonic-gate 		(void)skipwh();
3170Sstevel@tonic-gate 		seof = getchar();
3180Sstevel@tonic-gate 		if (endcmd(seof) || any(seof, "gcr")) {
3190Sstevel@tonic-gate 			ungetchar(seof);
3200Sstevel@tonic-gate 			goto redo;
3210Sstevel@tonic-gate 		}
3220Sstevel@tonic-gate 		if (isalpha(seof) || isdigit(seof))
3230Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("Substitute needs re") :
3240Sstevel@tonic-gate gettext("Missing regular expression for substitute"));
3250Sstevel@tonic-gate 		seof = vi_compile(seof, 1);
3260Sstevel@tonic-gate 		uselastre = 1;
3270Sstevel@tonic-gate 		comprhs(seof);
3280Sstevel@tonic-gate 		gsubf = cflag = 0;
3290Sstevel@tonic-gate 		break;
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	case '~':
3320Sstevel@tonic-gate 		uselastre = 1;
3330Sstevel@tonic-gate 		/* fall into ... */
3340Sstevel@tonic-gate 	case '&':
3350Sstevel@tonic-gate 	redo:
3360Sstevel@tonic-gate 		if (re == NULL || re->Expbuf[1] == 0)
3370Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("No previous re") :
3380Sstevel@tonic-gate gettext("No previous regular expression"));
3390Sstevel@tonic-gate 		if (subre == NULL || subre->Expbuf[1] == 0)
3400Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("No previous substitute re") :
3410Sstevel@tonic-gate gettext("No previous substitute to repeat"));
3420Sstevel@tonic-gate 		break;
3430Sstevel@tonic-gate 	}
3440Sstevel@tonic-gate 	for (;;) {
3450Sstevel@tonic-gate 		c = getchar();
3460Sstevel@tonic-gate 		switch (c) {
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 		case 'g':
3490Sstevel@tonic-gate 			gsubf = !gsubf;
3500Sstevel@tonic-gate 			continue;
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 		case 'c':
3530Sstevel@tonic-gate 			cflag = !cflag;
3540Sstevel@tonic-gate 			continue;
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 		case 'r':
3570Sstevel@tonic-gate 			uselastre = 1;
3580Sstevel@tonic-gate 			continue;
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 		default:
3610Sstevel@tonic-gate 			ungetchar(c);
3620Sstevel@tonic-gate 			setcount();
3630Sstevel@tonic-gate 			donewline();
3640Sstevel@tonic-gate 			if (uselastre)
3650Sstevel@tonic-gate 				savere(&subre);
3660Sstevel@tonic-gate 			else
3670Sstevel@tonic-gate 				resre(subre);
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 			/*
3700Sstevel@tonic-gate 			 * The % by itself on the right hand side means
3710Sstevel@tonic-gate 			 * that the previous value of the right hand side
3720Sstevel@tonic-gate 			 * should be used. A -1 is used to indicate no
3730Sstevel@tonic-gate 			 * previously remembered search string.
3740Sstevel@tonic-gate 			 */
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 			if (rhsbuf[0] == '%' && rhsbuf[1] == 0)
3770Sstevel@tonic-gate 				if (remflg == -1)
3780Sstevel@tonic-gate 					error(gettext("No previously remembered string"));
3790Sstevel@tonic-gate 			        else
3800Sstevel@tonic-gate 					strcpy(rhsbuf, remem);
3810Sstevel@tonic-gate 			else {
3820Sstevel@tonic-gate 				strcpy(remem, rhsbuf);
3830Sstevel@tonic-gate 				remflg = 1;
3840Sstevel@tonic-gate 			}
3850Sstevel@tonic-gate 			return (gsubf);
3860Sstevel@tonic-gate 		}
3870Sstevel@tonic-gate 	}
3880Sstevel@tonic-gate }
3890Sstevel@tonic-gate 
390*802Scf46844 void
391*802Scf46844 comprhs(int seof)
3920Sstevel@tonic-gate {
3930Sstevel@tonic-gate 	unsigned char *rp, *orp;
3940Sstevel@tonic-gate 	int c;
3950Sstevel@tonic-gate 	unsigned char orhsbuf[RHSSIZE];
3960Sstevel@tonic-gate 	char	multi[MB_LEN_MAX + 1];
3970Sstevel@tonic-gate 	int	len;
3980Sstevel@tonic-gate 	wchar_t	wc;
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	rp = rhsbuf;
4010Sstevel@tonic-gate 	CP(orhsbuf, rp);
4020Sstevel@tonic-gate 	for (;;) {
4030Sstevel@tonic-gate 		c = peekchar();
4040Sstevel@tonic-gate 		if (c == seof) {
4050Sstevel@tonic-gate 			(void) getchar();
4060Sstevel@tonic-gate 			break;
4070Sstevel@tonic-gate 		}
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 		if (!isascii(c) && c != EOF) {
4100Sstevel@tonic-gate 			if ((len = _mbftowc(multi, &wc, getchar, &peekc)) > 0) {
4110Sstevel@tonic-gate 				if ((rp + len) >= &rhsbuf[RHSSIZE - 1])
4120Sstevel@tonic-gate 					goto toobig;
4130Sstevel@tonic-gate 				strncpy(rp, multi, len);
4140Sstevel@tonic-gate 				rp += len;
4150Sstevel@tonic-gate 				continue;
4160Sstevel@tonic-gate 			}
4170Sstevel@tonic-gate 		}
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 		(void) getchar();
4200Sstevel@tonic-gate 		switch (c) {
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 		case '\\':
4230Sstevel@tonic-gate 			c = peekchar();
4240Sstevel@tonic-gate 			if (c == EOF) {
4250Sstevel@tonic-gate 				(void) getchar();
4260Sstevel@tonic-gate 				error(gettext("Replacement string ends with \\"));
4270Sstevel@tonic-gate 			}
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 			if (!isascii(c)) {
4300Sstevel@tonic-gate 				*rp++ = '\\';
4310Sstevel@tonic-gate 				if ((len = _mbftowc(multi, &wc, getchar, &peekc)) > 0) {
4320Sstevel@tonic-gate 					if ((rp + len) >= &rhsbuf[RHSSIZE - 1])
4330Sstevel@tonic-gate 						goto over_flow;
4340Sstevel@tonic-gate 					strncpy(rp, multi, len);
4350Sstevel@tonic-gate 					rp += len;
4360Sstevel@tonic-gate 					continue;
4370Sstevel@tonic-gate 				}
4380Sstevel@tonic-gate 			}
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 			(void) getchar();
4410Sstevel@tonic-gate 			if (value(vi_MAGIC)) {
4420Sstevel@tonic-gate 				/*
4430Sstevel@tonic-gate 				 * When "magic", \& turns into a plain &,
4440Sstevel@tonic-gate 				 * and all other chars work fine quoted.
4450Sstevel@tonic-gate 				 */
4460Sstevel@tonic-gate 				if (c != '&') {
4470Sstevel@tonic-gate 					if(rp >= &rhsbuf[RHSSIZE - 1]) {
4480Sstevel@tonic-gate 						*rp=0;
4490Sstevel@tonic-gate 						error(value(vi_TERSE) ?
4500Sstevel@tonic-gate gettext("Replacement pattern too long") :
4510Sstevel@tonic-gate gettext("Replacement pattern too long - limit 256 characters"));
4520Sstevel@tonic-gate 					}
4530Sstevel@tonic-gate 					*rp++ = '\\';
4540Sstevel@tonic-gate 				}
4550Sstevel@tonic-gate 				break;
4560Sstevel@tonic-gate 			}
4570Sstevel@tonic-gate magic:
4580Sstevel@tonic-gate 			if (c == '~') {
4590Sstevel@tonic-gate 				for (orp = orhsbuf; *orp; *rp++ = *orp++)
4600Sstevel@tonic-gate 					if (rp >= &rhsbuf[RHSSIZE - 1])
4610Sstevel@tonic-gate 						goto toobig;
4620Sstevel@tonic-gate 				continue;
4630Sstevel@tonic-gate 			}
4640Sstevel@tonic-gate 			if(rp >= &rhsbuf[RHSSIZE - 1]) {
4650Sstevel@tonic-gate over_flow:
4660Sstevel@tonic-gate 				*rp=0;
4670Sstevel@tonic-gate 				error(value(vi_TERSE) ?
4680Sstevel@tonic-gate gettext("Replacement pattern too long") :
4690Sstevel@tonic-gate gettext("Replacement pattern too long - limit 256 characters"));
4700Sstevel@tonic-gate 			}
4710Sstevel@tonic-gate 			*rp++ = '\\';
4720Sstevel@tonic-gate 			break;
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 		case '\n':
4750Sstevel@tonic-gate 		case EOF:
4760Sstevel@tonic-gate 			if (!(globp && globp[0])) {
4770Sstevel@tonic-gate 				ungetchar(c);
4780Sstevel@tonic-gate 				goto endrhs;
4790Sstevel@tonic-gate 			}
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 		case '~':
4820Sstevel@tonic-gate 		case '&':
4830Sstevel@tonic-gate 			if (value(vi_MAGIC))
4840Sstevel@tonic-gate 				goto magic;
4850Sstevel@tonic-gate 			break;
4860Sstevel@tonic-gate 		}
4870Sstevel@tonic-gate 		if (rp >= &rhsbuf[RHSSIZE - 1]) {
4880Sstevel@tonic-gate toobig:
4890Sstevel@tonic-gate 			*rp = 0;
4900Sstevel@tonic-gate 			error(value(vi_TERSE) ?
4910Sstevel@tonic-gate gettext("Replacement pattern too long") :
4920Sstevel@tonic-gate gettext("Replacement pattern too long - limit 256 characters"));
4930Sstevel@tonic-gate 		}
4940Sstevel@tonic-gate 		*rp++ = c;
4950Sstevel@tonic-gate 	}
4960Sstevel@tonic-gate endrhs:
4970Sstevel@tonic-gate 	*rp++ = 0;
4980Sstevel@tonic-gate }
4990Sstevel@tonic-gate 
500*802Scf46844 int
501*802Scf46844 getsub(void)
5020Sstevel@tonic-gate {
5030Sstevel@tonic-gate 	unsigned char *p;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	if ((p = linebp) == 0)
5060Sstevel@tonic-gate 		return (EOF);
5070Sstevel@tonic-gate 	strcLIN(p);
5080Sstevel@tonic-gate 	linebp = 0;
5090Sstevel@tonic-gate 	return (0);
5100Sstevel@tonic-gate }
5110Sstevel@tonic-gate 
512*802Scf46844 int
513*802Scf46844 dosubcon(bool f, line *a)
5140Sstevel@tonic-gate {
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	if (execute(f, a) == 0)
5170Sstevel@tonic-gate 		return (0);
5180Sstevel@tonic-gate 	if (confirmed(a)) {
5190Sstevel@tonic-gate 		dosub();
5200Sstevel@tonic-gate 		scount++;
5210Sstevel@tonic-gate 	}
5220Sstevel@tonic-gate 	return (1);
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate 
525*802Scf46844 int
526*802Scf46844 confirmed(line *a)
5270Sstevel@tonic-gate {
5280Sstevel@tonic-gate 	int c, cnt, ch;
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	if (cflag == 0)
5310Sstevel@tonic-gate 		return (1);
5320Sstevel@tonic-gate 	pofix();
5330Sstevel@tonic-gate 	pline(lineno(a));
5340Sstevel@tonic-gate 	if (inopen)
5350Sstevel@tonic-gate 		putchar('\n' | QUOTE);
5360Sstevel@tonic-gate 	c = lcolumn(loc1);
5370Sstevel@tonic-gate 	ugo(c, ' ');
5380Sstevel@tonic-gate 	ugo(lcolumn(loc2) - c, '^');
5390Sstevel@tonic-gate 	flush();
5400Sstevel@tonic-gate 	cnt = 0;
5410Sstevel@tonic-gate bkup:
5420Sstevel@tonic-gate 	ch = c = getkey();
5430Sstevel@tonic-gate again:
5440Sstevel@tonic-gate 	if (c == '\b') {
5450Sstevel@tonic-gate 		if ((inopen)
5460Sstevel@tonic-gate 		 && (cnt > 0)) {
5470Sstevel@tonic-gate 			putchar('\b' | QUOTE);
5480Sstevel@tonic-gate 			putchar(' ');
5490Sstevel@tonic-gate 			putchar('\b' | QUOTE), flush();
5500Sstevel@tonic-gate 			cnt --;
5510Sstevel@tonic-gate 		}
5520Sstevel@tonic-gate 		goto bkup;
5530Sstevel@tonic-gate 	}
5540Sstevel@tonic-gate 	if (c == '\r')
5550Sstevel@tonic-gate 		c = '\n';
5560Sstevel@tonic-gate 	if (inopen && MB_CUR_MAX == 1 || c < 0200) {
5570Sstevel@tonic-gate 		putchar(c);
5580Sstevel@tonic-gate 		flush();
5590Sstevel@tonic-gate 		cnt++;
5600Sstevel@tonic-gate 	}
5610Sstevel@tonic-gate 	if (c != '\n' && c != EOF) {
5620Sstevel@tonic-gate 		c = getkey();
5630Sstevel@tonic-gate 		goto again;
5640Sstevel@tonic-gate 	}
5650Sstevel@tonic-gate 	noteinp();
5660Sstevel@tonic-gate 	return (ch == 'y');
5670Sstevel@tonic-gate }
5680Sstevel@tonic-gate 
569*802Scf46844 void
570*802Scf46844 ugo(int cnt, int with)
5710Sstevel@tonic-gate {
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	if (cnt > 0)
5740Sstevel@tonic-gate 		do
5750Sstevel@tonic-gate 			putchar(with);
5760Sstevel@tonic-gate 		while (--cnt > 0);
5770Sstevel@tonic-gate }
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate int	casecnt;
5800Sstevel@tonic-gate bool	destuc;
5810Sstevel@tonic-gate 
582*802Scf46844 void
583*802Scf46844 dosub(void)
5840Sstevel@tonic-gate {
5850Sstevel@tonic-gate 	unsigned char *lp, *sp, *rp;
5860Sstevel@tonic-gate 	int c;
5870Sstevel@tonic-gate 	int	len;
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	lp = linebuf;
5900Sstevel@tonic-gate 	sp = genbuf;
5910Sstevel@tonic-gate 	rp = rhsbuf;
5920Sstevel@tonic-gate 	while (lp < (unsigned char *)loc1)
5930Sstevel@tonic-gate 		*sp++ = *lp++;
5940Sstevel@tonic-gate 	casecnt = 0;
5950Sstevel@tonic-gate 	/*
5960Sstevel@tonic-gate 	 * Caution: depending on the hardware, c will be either sign
5970Sstevel@tonic-gate 	 * extended or not if C&QUOTE is set.  Thus, on a VAX, c will
5980Sstevel@tonic-gate 	 * be < 0, but on a 3B, c will be >= 128.
5990Sstevel@tonic-gate 	 */
6000Sstevel@tonic-gate 	while (c = *rp) {
6010Sstevel@tonic-gate 		if ((len = mblen((char *)rp, MB_CUR_MAX)) <= 0)
6020Sstevel@tonic-gate 			len = 1;
6030Sstevel@tonic-gate 		/* ^V <return> from vi to split lines */
6040Sstevel@tonic-gate 		if (c == '\r')
6050Sstevel@tonic-gate 			c = '\n';
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 		if (c == '\\') {
6080Sstevel@tonic-gate 			rp++;
6090Sstevel@tonic-gate 			if ((len = mblen((char *)rp, MB_CUR_MAX)) <= 0)
6100Sstevel@tonic-gate 				len = 1;
6110Sstevel@tonic-gate 			switch (c = *rp++) {
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 			case '&':
6140Sstevel@tonic-gate 				sp = place(sp, loc1, loc2);
6150Sstevel@tonic-gate 				if (sp == 0)
6160Sstevel@tonic-gate 					goto ovflo;
6170Sstevel@tonic-gate 				continue;
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 			case 'l':
6200Sstevel@tonic-gate 				casecnt = 1;
6210Sstevel@tonic-gate 				destuc = 0;
6220Sstevel@tonic-gate 				continue;
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 			case 'L':
6250Sstevel@tonic-gate 				casecnt = LBSIZE;
6260Sstevel@tonic-gate 				destuc = 0;
6270Sstevel@tonic-gate 				continue;
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 			case 'u':
6300Sstevel@tonic-gate 				casecnt = 1;
6310Sstevel@tonic-gate 				destuc = 1;
6320Sstevel@tonic-gate 				continue;
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 			case 'U':
6350Sstevel@tonic-gate 				casecnt = LBSIZE;
6360Sstevel@tonic-gate 				destuc = 1;
6370Sstevel@tonic-gate 				continue;
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 			case 'E':
6400Sstevel@tonic-gate 			case 'e':
6410Sstevel@tonic-gate 				casecnt = 0;
6420Sstevel@tonic-gate 				continue;
6430Sstevel@tonic-gate 			}
6440Sstevel@tonic-gate 			if(re != NULL && c >= '1' && c < re->Nbra + '1') {
6450Sstevel@tonic-gate 				sp = place(sp, braslist[c - '1'] , braelist[c - '1']);
6460Sstevel@tonic-gate 				if (sp == 0)
6470Sstevel@tonic-gate 					goto ovflo;
6480Sstevel@tonic-gate 				continue;
6490Sstevel@tonic-gate 			}
6500Sstevel@tonic-gate 			rp--;
6510Sstevel@tonic-gate 		}
6520Sstevel@tonic-gate 		if (len > 1) {
6530Sstevel@tonic-gate 			if ((sp + len) >= &genbuf[LBSIZE])
6540Sstevel@tonic-gate 				goto ovflo;
6550Sstevel@tonic-gate 			strncpy(sp, rp, len);
6560Sstevel@tonic-gate 		} else {
6570Sstevel@tonic-gate 			if (casecnt)
6580Sstevel@tonic-gate 				*sp = fixcase(c);
6590Sstevel@tonic-gate 			else
6600Sstevel@tonic-gate 				*sp = c;
6610Sstevel@tonic-gate 		}
6620Sstevel@tonic-gate 		sp += len; rp += len;
6630Sstevel@tonic-gate 		if (sp >= &genbuf[LBSIZE])
6640Sstevel@tonic-gate ovflo:
6650Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("Line overflow") :
6660Sstevel@tonic-gate gettext("Line overflow in substitute"));
6670Sstevel@tonic-gate 	}
6680Sstevel@tonic-gate 	lp = (unsigned char *)loc2;
6690Sstevel@tonic-gate 	loc2 = (char *)(linebuf + (sp - genbuf));
6700Sstevel@tonic-gate 	while (*sp++ = *lp++)
6710Sstevel@tonic-gate 		if (sp >= &genbuf[LBSIZE])
6720Sstevel@tonic-gate 			goto ovflo;
6730Sstevel@tonic-gate 	strcLIN(genbuf);
6740Sstevel@tonic-gate }
6750Sstevel@tonic-gate 
676*802Scf46844 int
677*802Scf46844 fixcase(int c)
6780Sstevel@tonic-gate {
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 	if (casecnt == 0)
6810Sstevel@tonic-gate 		return (c);
6820Sstevel@tonic-gate 	casecnt--;
6830Sstevel@tonic-gate 	if (destuc) {
6840Sstevel@tonic-gate 		if (islower(c))
6850Sstevel@tonic-gate 			c = toupper(c);
6860Sstevel@tonic-gate 	} else
6870Sstevel@tonic-gate 		if (isupper(c))
6880Sstevel@tonic-gate 			c = tolower(c);
6890Sstevel@tonic-gate 	return (c);
6900Sstevel@tonic-gate }
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate unsigned char *
6930Sstevel@tonic-gate place(sp, l1, l2)
6940Sstevel@tonic-gate 	unsigned char *sp, *l1, *l2;
6950Sstevel@tonic-gate {
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	while (l1 < l2) {
6980Sstevel@tonic-gate 		*sp++ = fixcase(*l1++);
6990Sstevel@tonic-gate 		if (sp >= &genbuf[LBSIZE])
7000Sstevel@tonic-gate 			return (0);
7010Sstevel@tonic-gate 	}
7020Sstevel@tonic-gate 	return (sp);
7030Sstevel@tonic-gate }
7040Sstevel@tonic-gate 
705*802Scf46844 void
706*802Scf46844 snote(int total, int nlines)
7070Sstevel@tonic-gate {
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	if (!notable(total))
7100Sstevel@tonic-gate 		return;
7110Sstevel@tonic-gate 	if (nlines != 1 && nlines != total)
712*802Scf46844 		viprintf(mesg(value(vi_TERSE) ?
7130Sstevel@tonic-gate 			/*
7140Sstevel@tonic-gate 			 * TRANSLATION_NOTE
7150Sstevel@tonic-gate 			 *	Reference order of arguments must not
7160Sstevel@tonic-gate 			 *	be changed using '%digit$', since vi's
717*802Scf46844 			 *	viprintf() does not support it.
7180Sstevel@tonic-gate 			 */
7190Sstevel@tonic-gate 			    gettext("%d subs on %d lines") :
7200Sstevel@tonic-gate 			/*
7210Sstevel@tonic-gate 			 * TRANSLATION_NOTE
7220Sstevel@tonic-gate 			 *	Reference order of arguments must not
7230Sstevel@tonic-gate 			 *	be changed using '%digit$', since vi's
724*802Scf46844 			 *	viprintf() does not support it.
7250Sstevel@tonic-gate 			 */
7260Sstevel@tonic-gate 			    gettext("%d substitutions on %d lines")),
7270Sstevel@tonic-gate 		       total, nlines);
7280Sstevel@tonic-gate 	else
729*802Scf46844 		viprintf(mesg(value(vi_TERSE) ?
7300Sstevel@tonic-gate 			    gettext("%d subs") :
7310Sstevel@tonic-gate 			    gettext("%d substitutions")),
7320Sstevel@tonic-gate 		       total);
7330Sstevel@tonic-gate 	noonl();
7340Sstevel@tonic-gate 	flush();
7350Sstevel@tonic-gate }
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate #ifdef XPG4
7380Sstevel@tonic-gate #include <regex.h>
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate extern int regcomp_flags;	/* use to specify cflags for regcomp() */
7410Sstevel@tonic-gate #endif /* XPG4 */
7420Sstevel@tonic-gate 
743*802Scf46844 int
744*802Scf46844 vi_compile(int eof, int oknl)
7450Sstevel@tonic-gate {
7460Sstevel@tonic-gate 	int c;
7470Sstevel@tonic-gate 	unsigned char *gp, *p1;
7480Sstevel@tonic-gate 	unsigned char *rhsp;
7490Sstevel@tonic-gate 	unsigned char rebuf[LBSIZE];
7500Sstevel@tonic-gate 	char	multi[MB_LEN_MAX + 1];
7510Sstevel@tonic-gate 	int	len;
7520Sstevel@tonic-gate 	wchar_t	wc;
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate #ifdef XPG4
7550Sstevel@tonic-gate 	/*
7560Sstevel@tonic-gate 	 * reset cflags to plain BRE
7570Sstevel@tonic-gate 	 * if \< and/or \> is specified, REG_WORDS is set.
7580Sstevel@tonic-gate 	 */
7590Sstevel@tonic-gate 	regcomp_flags = 0;
7600Sstevel@tonic-gate #endif /* XPG4 */
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	gp = genbuf;
7630Sstevel@tonic-gate 	if (isalpha(eof) || isdigit(eof))
7640Sstevel@tonic-gate error(gettext("Regular expressions cannot be delimited by letters or digits"));
7650Sstevel@tonic-gate 	if(eof >= 0200 && MB_CUR_MAX > 1)
7660Sstevel@tonic-gate error(gettext("Regular expressions cannot be delimited by multibyte characters"));
7670Sstevel@tonic-gate 	c = getchar();
7680Sstevel@tonic-gate 	if (eof == '\\')
7690Sstevel@tonic-gate 		switch (c) {
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 		case '/':
7720Sstevel@tonic-gate 		case '?':
7730Sstevel@tonic-gate 			if (scanre == NULL || scanre->Expbuf[1] == 0)
7740Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("No previous scan re") :
7750Sstevel@tonic-gate gettext("No previous scanning regular expression"));
7760Sstevel@tonic-gate 			resre(scanre);
7770Sstevel@tonic-gate 			return (c);
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 		case '&':
7800Sstevel@tonic-gate 			if (subre == NULL || subre->Expbuf[1] == 0)
7810Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("No previous substitute re") :
7820Sstevel@tonic-gate gettext("No previous substitute regular expression"));
7830Sstevel@tonic-gate 			resre(subre);
7840Sstevel@tonic-gate 			return (c);
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 		default:
7870Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("Badly formed re") :
7880Sstevel@tonic-gate gettext("Regular expression \\ must be followed by / or ?"));
7890Sstevel@tonic-gate 		}
7900Sstevel@tonic-gate 	if (c == eof || c == '\n' || c == EOF) {
7910Sstevel@tonic-gate 		if (re == NULL || re->Expbuf[1] == 0)
7920Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("No previous re") :
7930Sstevel@tonic-gate gettext("No previous regular expression"));
7940Sstevel@tonic-gate 		if (c == '\n' && oknl == 0)
7950Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("Missing closing delimiter") :
7960Sstevel@tonic-gate gettext("Missing closing delimiter for regular expression"));
7970Sstevel@tonic-gate 		if (c != eof)
7980Sstevel@tonic-gate 			ungetchar(c);
7990Sstevel@tonic-gate 		return (eof);
8000Sstevel@tonic-gate 	}
8010Sstevel@tonic-gate 	gp = genbuf;
8020Sstevel@tonic-gate 	if (c == '^') {
8030Sstevel@tonic-gate 		*gp++ = c;
8040Sstevel@tonic-gate 		c = getchar();
8050Sstevel@tonic-gate 	}
8060Sstevel@tonic-gate 	ungetchar(c);
8070Sstevel@tonic-gate 	for (;;) {
8080Sstevel@tonic-gate 		c = getchar();
8090Sstevel@tonic-gate 		if (c == eof || c == EOF) {
8100Sstevel@tonic-gate 			if (c == EOF)
8110Sstevel@tonic-gate 				ungetchar(c);
8120Sstevel@tonic-gate 			goto out;
8130Sstevel@tonic-gate 		}
8140Sstevel@tonic-gate 		if (gp >= &genbuf[LBSIZE - 3])
8150Sstevel@tonic-gate complex:
816*802Scf46844 			cerror(value(vi_TERSE) ?
817*802Scf46844 			    (unsigned char *)gettext("Re too complex") :
818*802Scf46844 			    (unsigned char *)
819*802Scf46844 			    gettext("Regular expression too complicated"));
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 		if (!(isascii(c) || MB_CUR_MAX == 1)) {
8220Sstevel@tonic-gate 			ungetchar(c);
8230Sstevel@tonic-gate 			if ((len = _mbftowc(multi, &wc, getchar, &peekc)) >= 1) {
8240Sstevel@tonic-gate 				if ((gp + len) >= &genbuf[LBSIZE - 3])
8250Sstevel@tonic-gate 					goto complex;
8260Sstevel@tonic-gate 				strncpy(gp, multi, len);
8270Sstevel@tonic-gate 				gp += len;
8280Sstevel@tonic-gate 				continue;
8290Sstevel@tonic-gate 			}
8300Sstevel@tonic-gate 			(void) getchar();
8310Sstevel@tonic-gate 		}
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 		switch (c) {
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 		case '\\':
8360Sstevel@tonic-gate 			c = getchar();
8370Sstevel@tonic-gate 			if (!isascii(c)) {
8380Sstevel@tonic-gate 				ungetchar(c);
8390Sstevel@tonic-gate 				if ((len = _mbftowc(multi, &wc, getchar, &peekc)) >= 1) {
8400Sstevel@tonic-gate 					if ((gp + len) >= &genbuf[LBSIZE - 3])
8410Sstevel@tonic-gate 						goto complex;
8420Sstevel@tonic-gate 					*gp++ = '\\';
8430Sstevel@tonic-gate 					strncpy(gp, multi, len);
8440Sstevel@tonic-gate 					gp += len;
8450Sstevel@tonic-gate 					continue;
8460Sstevel@tonic-gate 				}
8470Sstevel@tonic-gate 				(void) getchar();
8480Sstevel@tonic-gate 			}
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 			switch (c) {
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 			case '<':
8530Sstevel@tonic-gate 			case '>':
8540Sstevel@tonic-gate #ifdef XPG4
8550Sstevel@tonic-gate 				regcomp_flags = REG_WORDS;
8560Sstevel@tonic-gate 				/*FALLTHRU*/
8570Sstevel@tonic-gate #endif /* XPG4 */
8580Sstevel@tonic-gate 			case '(':
8590Sstevel@tonic-gate 			case ')':
8600Sstevel@tonic-gate 			case '{':
8610Sstevel@tonic-gate 			case '}':
8620Sstevel@tonic-gate 			case '$':
8630Sstevel@tonic-gate 			case '^':
8640Sstevel@tonic-gate 			case '\\':
8650Sstevel@tonic-gate 				*gp++ = '\\';
8660Sstevel@tonic-gate 				*gp++ = c;
8670Sstevel@tonic-gate 				continue;
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 			case 'n':
8700Sstevel@tonic-gate 				*gp++ = c;
8710Sstevel@tonic-gate 				continue;
8720Sstevel@tonic-gate 			}
8730Sstevel@tonic-gate 			if(c >= '0' && c <= '9') {
8740Sstevel@tonic-gate 				*gp++ = '\\';
8750Sstevel@tonic-gate 				*gp++ = c;
8760Sstevel@tonic-gate 				continue;
8770Sstevel@tonic-gate 			}
8780Sstevel@tonic-gate 			if (value(vi_MAGIC) == 0)
8790Sstevel@tonic-gate magic:
8800Sstevel@tonic-gate 			switch (c) {
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 			case '.':
8830Sstevel@tonic-gate 				*gp++ = '.';
8840Sstevel@tonic-gate 				continue;
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 			case '~':
8870Sstevel@tonic-gate 				rhsp = rhsbuf;
8880Sstevel@tonic-gate 				while (*rhsp) {
8890Sstevel@tonic-gate 					if (!isascii(*rhsp)) {
8900Sstevel@tonic-gate 						if ((len = mbtowc((wchar_t *)0, (char *)rhsp, MB_CUR_MAX)) > 1) {
8910Sstevel@tonic-gate 							if ((gp + len) >= &genbuf[LBSIZE-2])
8920Sstevel@tonic-gate 								goto complex;
8930Sstevel@tonic-gate 							strncpy(gp, rhsp, len);
8940Sstevel@tonic-gate 							rhsp += len; gp += len;
8950Sstevel@tonic-gate 							continue;
8960Sstevel@tonic-gate 						}
8970Sstevel@tonic-gate 					}
8980Sstevel@tonic-gate 					len = 1;
8990Sstevel@tonic-gate 					if (*rhsp == '\\') {
9000Sstevel@tonic-gate 						c = *++rhsp;
9010Sstevel@tonic-gate 						if (c == '&')
902*802Scf46844 cerror(value(vi_TERSE) ? (unsigned char *)
903*802Scf46844 gettext("Replacement pattern contains &") :
904*802Scf46844 (unsigned char *)gettext("Replacement pattern contains & - cannot use in re"));
9050Sstevel@tonic-gate 						if (c >= '1' && c <= '9')
906*802Scf46844 cerror(value(vi_TERSE) ? (unsigned char *)
907*802Scf46844 gettext("Replacement pattern contains \\d") :
908*802Scf46844 (unsigned char *)
9090Sstevel@tonic-gate gettext("Replacement pattern contains \\d - cannot use in re"));
9100Sstevel@tonic-gate 						if ((len = mbtowc((wchar_t *)0, (char *)rhsp, MB_CUR_MAX)) <= 1) {
9110Sstevel@tonic-gate 							len = 1;
9120Sstevel@tonic-gate 							if(any(c, ".\\*[$"))
9130Sstevel@tonic-gate 								*gp++ = '\\';
9140Sstevel@tonic-gate 						}
9150Sstevel@tonic-gate 					}
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 					if ((gp + len) >= &genbuf[LBSIZE-2])
9180Sstevel@tonic-gate 						goto complex;
9190Sstevel@tonic-gate 					if (len == 1) {
9200Sstevel@tonic-gate 						c = *rhsp++;
9210Sstevel@tonic-gate 						*gp++ = (value(vi_IGNORECASE) ? tolower(c) : c);
9220Sstevel@tonic-gate 					} else {
9230Sstevel@tonic-gate 						strncpy(gp, rhsp, len);
9240Sstevel@tonic-gate 						gp += len; rhsp += len;
9250Sstevel@tonic-gate 					}
9260Sstevel@tonic-gate 				}
9270Sstevel@tonic-gate 				continue;
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 			case '*':
9300Sstevel@tonic-gate 				*gp++ = '*';
9310Sstevel@tonic-gate 				continue;
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 			case '[':
9340Sstevel@tonic-gate 				*gp++ = '[';
9350Sstevel@tonic-gate 				c = getchar();
9360Sstevel@tonic-gate 				if (c == '^') {
9370Sstevel@tonic-gate 					*gp++ = '^';
9380Sstevel@tonic-gate 					c = getchar();
9390Sstevel@tonic-gate 				}
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 				do {
9420Sstevel@tonic-gate 					if (!isascii(c) && c != EOF) {
9430Sstevel@tonic-gate 						ungetchar(c);
9440Sstevel@tonic-gate 						if ((len = _mbftowc(multi, &wc, getchar, &peekc)) >= 1) {
9450Sstevel@tonic-gate 							if ((gp + len)>= &genbuf[LBSIZE-4])
9460Sstevel@tonic-gate 								goto complex;
9470Sstevel@tonic-gate 							strncpy(gp, multi, len);
9480Sstevel@tonic-gate 							gp += len;
9490Sstevel@tonic-gate 							c = getchar();
9500Sstevel@tonic-gate 							continue;
9510Sstevel@tonic-gate 						}
9520Sstevel@tonic-gate 						(void) getchar();
9530Sstevel@tonic-gate 					}
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 					if (gp >= &genbuf[LBSIZE-4])
9560Sstevel@tonic-gate 						goto complex;
9570Sstevel@tonic-gate 					if(c == '\\' && peekchar() == ']') {
9580Sstevel@tonic-gate 						(void)getchar();
9590Sstevel@tonic-gate 						*gp++ = '\\';
9600Sstevel@tonic-gate 						*gp++ = ']';
9610Sstevel@tonic-gate 					}
9620Sstevel@tonic-gate 					else if (c == '\n' || c == EOF)
963*802Scf46844 						cerror((unsigned char *)
964*802Scf46844 						    gettext("Missing ]"));
9650Sstevel@tonic-gate 					else
9660Sstevel@tonic-gate 						*gp++ = (value(vi_IGNORECASE) ? tolower(c) : c);
9670Sstevel@tonic-gate 					c = getchar();
9680Sstevel@tonic-gate 				} while(c != ']');
9690Sstevel@tonic-gate 				*gp++ = ']';
9700Sstevel@tonic-gate 				continue;
9710Sstevel@tonic-gate 			}
9720Sstevel@tonic-gate 			if (c == EOF) {
9730Sstevel@tonic-gate 				ungetchar(EOF);
9740Sstevel@tonic-gate 				*gp++ = '\\';
9750Sstevel@tonic-gate 				*gp++ = '\\';
9760Sstevel@tonic-gate 				continue;
9770Sstevel@tonic-gate 			}
9780Sstevel@tonic-gate 			if (c == '\n')
979*802Scf46844 cerror(value(vi_TERSE) ? (unsigned char *)gettext("No newlines in re's") :
980*802Scf46844 (unsigned char *)gettext("Can't escape newlines into regular expressions"));
9810Sstevel@tonic-gate 			*gp++ = '\\';
9820Sstevel@tonic-gate 			*gp++ = (value(vi_IGNORECASE) ? tolower(c) : c);
9830Sstevel@tonic-gate 			continue;
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 		case '\n':
9860Sstevel@tonic-gate 			if (oknl) {
9870Sstevel@tonic-gate 				ungetchar(c);
9880Sstevel@tonic-gate 				goto out;
9890Sstevel@tonic-gate 			}
990*802Scf46844 cerror(value(vi_TERSE) ? (unsigned char *)gettext("Badly formed re") :
991*802Scf46844 (unsigned char *)gettext("Missing closing delimiter for regular expression"));
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 		case '.':
9940Sstevel@tonic-gate 		case '~':
9950Sstevel@tonic-gate 		case '*':
9960Sstevel@tonic-gate 		case '[':
9970Sstevel@tonic-gate 			if (value(vi_MAGIC))
9980Sstevel@tonic-gate 				goto magic;
9990Sstevel@tonic-gate 			if(c != '~')
10000Sstevel@tonic-gate 				*gp++ = '\\';
10010Sstevel@tonic-gate defchar:
10020Sstevel@tonic-gate 		default:
10030Sstevel@tonic-gate 			*gp++ = (value(vi_IGNORECASE) ? tolower(c) : c);
10040Sstevel@tonic-gate 			continue;
10050Sstevel@tonic-gate 		}
10060Sstevel@tonic-gate 	}
10070Sstevel@tonic-gate out:
10080Sstevel@tonic-gate 	*gp++ = '\0';
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate #ifdef XPG4
10110Sstevel@tonic-gate 	/* see if our compiled RE's will fit in the re structure:	*/
10120Sstevel@tonic-gate 	if (regexc_size > EXPSIZ) {
10130Sstevel@tonic-gate 		/*
10140Sstevel@tonic-gate 		 * this should never happen. but it's critical that we
10150Sstevel@tonic-gate 		 * check here, otherwise .bss would get overwritten.
10160Sstevel@tonic-gate 		 */
1017*802Scf46844 		cerror(value(vi_TERSE) ? (unsigned char *)
1018*802Scf46844 		    gettext("RE's can't fit") :
1019*802Scf46844 		    (unsigned char *)gettext("Regular expressions can't fit"));
10200Sstevel@tonic-gate 		return(eof);
10210Sstevel@tonic-gate 	}
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	/*
10240Sstevel@tonic-gate 	 * We create re each time we need it.
10250Sstevel@tonic-gate 	 */
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	if (re == NULL || re == scanre || re == subre) {
10280Sstevel@tonic-gate 		if ((re = calloc(1, sizeof(struct regexp))) == NULL) {
10290Sstevel@tonic-gate 			error(gettext("out of memory"));
10300Sstevel@tonic-gate 			exit(errcnt);
10310Sstevel@tonic-gate 		}
10320Sstevel@tonic-gate 	} else {
10330Sstevel@tonic-gate 		regex_comp_free(&re->Expbuf);
10340Sstevel@tonic-gate 		memset(re, 0, sizeof(struct regexp));
10350Sstevel@tonic-gate 	}
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	compile((char *) genbuf, (char *) re->Expbuf, (char *) re->Expbuf
10380Sstevel@tonic-gate 	    + regexc_size);
10390Sstevel@tonic-gate #else /* !XPG4 */
10400Sstevel@tonic-gate 	(void) _compile((const char *)genbuf, (char *)re->Expbuf,
10410Sstevel@tonic-gate 		(char *)(re->Expbuf + sizeof (re->Expbuf)), 1);
10420Sstevel@tonic-gate #endif /* XPG4 */
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	if(regerrno)
10450Sstevel@tonic-gate 		switch(regerrno) {
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 		case 42:
1048*802Scf46844 cerror((unsigned char *)gettext("\\( \\) Imbalance"));
10490Sstevel@tonic-gate 		case 43:
1050*802Scf46844 cerror(value(vi_TERSE) ? (unsigned char *)gettext("Awash in \\('s!") :
1051*802Scf46844 (unsigned char *)
10520Sstevel@tonic-gate gettext("Too many \\('d subexpressions in a regular expression"));
10530Sstevel@tonic-gate 		case 50:
10540Sstevel@tonic-gate 			goto complex;
10550Sstevel@tonic-gate 		case 67:
1056*802Scf46844 cerror(value(vi_TERSE) ? (unsigned char *)gettext("Illegal byte sequence") :
1057*802Scf46844 (unsigned char *)gettext("Regular expression has illegal byte sequence"));
10580Sstevel@tonic-gate 		}
10590Sstevel@tonic-gate 	re->Nbra = nbra;
10600Sstevel@tonic-gate 	return(eof);
10610Sstevel@tonic-gate }
10620Sstevel@tonic-gate 
1063*802Scf46844 void
1064*802Scf46844 cerror(unsigned char *s)
10650Sstevel@tonic-gate {
10660Sstevel@tonic-gate 	if (re) {
10670Sstevel@tonic-gate 		re->Expbuf[0] = re->Expbuf[1] = 0;
10680Sstevel@tonic-gate 	}
10690Sstevel@tonic-gate 	error(s);
10700Sstevel@tonic-gate }
10710Sstevel@tonic-gate 
1072*802Scf46844 int
1073*802Scf46844 execute(int gf, line *addr)
10740Sstevel@tonic-gate {
10750Sstevel@tonic-gate 	unsigned char *p1, *p2;
10760Sstevel@tonic-gate 	char *start;
10770Sstevel@tonic-gate 	int c, i;
10780Sstevel@tonic-gate 	int ret;
10790Sstevel@tonic-gate 	int	len;
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 	if (gf) {
10820Sstevel@tonic-gate 		if (re == NULL || re->Expbuf[0])
10830Sstevel@tonic-gate 			return (0);
10840Sstevel@tonic-gate 		if(value(vi_IGNORECASE)) {
10850Sstevel@tonic-gate 			p1 = genbuf;
10860Sstevel@tonic-gate 			p2 = (unsigned char *)loc2;
10870Sstevel@tonic-gate 			while(c = *p2) {
10880Sstevel@tonic-gate 				if ((len = mblen((char *)p2, MB_CUR_MAX)) <= 0)
10890Sstevel@tonic-gate 					len = 1;
10900Sstevel@tonic-gate 				if (len == 1) {
10910Sstevel@tonic-gate 					*p1++ = tolower(c);
10920Sstevel@tonic-gate 					p2++;
10930Sstevel@tonic-gate 					continue;
10940Sstevel@tonic-gate 				}
10950Sstevel@tonic-gate 				strncpy(p1, p2, len);
10960Sstevel@tonic-gate 				p1 += len; p2 += len;
10970Sstevel@tonic-gate 			}
10980Sstevel@tonic-gate 			*p1 = '\0';
10990Sstevel@tonic-gate 			locs = (char *)genbuf;
11000Sstevel@tonic-gate 			p1 = genbuf;
11010Sstevel@tonic-gate 			start = loc2;
11020Sstevel@tonic-gate 		} else {
11030Sstevel@tonic-gate 			p1 = (unsigned char *)loc2;
11040Sstevel@tonic-gate 			locs = loc2;
11050Sstevel@tonic-gate 		}
11060Sstevel@tonic-gate 	} else {
11070Sstevel@tonic-gate 		if (addr == zero)
11080Sstevel@tonic-gate 			return (0);
11090Sstevel@tonic-gate 		p1 = linebuf;
11100Sstevel@tonic-gate 		getline(*addr);
11110Sstevel@tonic-gate 		if(value(vi_IGNORECASE)) {
11120Sstevel@tonic-gate 			p1 = genbuf;
11130Sstevel@tonic-gate 			p2 = linebuf;
11140Sstevel@tonic-gate 			while(c = *p2) {
11150Sstevel@tonic-gate 				if ((len = mblen((char *)p2, MB_CUR_MAX)) <= 0)
11160Sstevel@tonic-gate 					len = 1;
11170Sstevel@tonic-gate 				if (len == 1) {
11180Sstevel@tonic-gate 					*p1++ = tolower(c);
11190Sstevel@tonic-gate 					p2++;
11200Sstevel@tonic-gate 					continue;
11210Sstevel@tonic-gate 				}
11220Sstevel@tonic-gate 				strncpy(p1, p2, len);
11230Sstevel@tonic-gate 				p1 += len; p2 += len;
11240Sstevel@tonic-gate 			}
11250Sstevel@tonic-gate 			*p1 = '\0';
11260Sstevel@tonic-gate 			p1 = genbuf;
11270Sstevel@tonic-gate 			start = (char *)linebuf;
11280Sstevel@tonic-gate 		}
11290Sstevel@tonic-gate 		locs = (char *)0;
11300Sstevel@tonic-gate 	}
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	ret = step((char *)p1, (char *)re->Expbuf);
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	if(value(vi_IGNORECASE) && ret) {
11350Sstevel@tonic-gate 		loc1 = start + (loc1 - (char *)genbuf);
11360Sstevel@tonic-gate 		loc2 = start + (loc2 - (char *)genbuf);
11370Sstevel@tonic-gate 		for(i = 0; i < NBRA; i++) {
11380Sstevel@tonic-gate 			braslist[i] = start + (braslist[i] - (char *)genbuf);
11390Sstevel@tonic-gate 			braelist[i] = start + (braelist[i] - (char *)genbuf);
11400Sstevel@tonic-gate 		}
11410Sstevel@tonic-gate 	}
11420Sstevel@tonic-gate 	return ret;
11430Sstevel@tonic-gate }
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate /*
11460Sstevel@tonic-gate  *  Initialize the compiled regular-expression storage areas (called from
11470Sstevel@tonic-gate  *  main()).
11480Sstevel@tonic-gate  */
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate void init_re (void)
11510Sstevel@tonic-gate {
11520Sstevel@tonic-gate #ifdef XPG4
11530Sstevel@tonic-gate 	re = scanre = subre = NULL;
11540Sstevel@tonic-gate #else /* !XPG4 */
11550Sstevel@tonic-gate 	if ((re = calloc(1, sizeof(struct regexp))) == NULL) {
11560Sstevel@tonic-gate 		error(gettext("out of memory"));
11570Sstevel@tonic-gate 		exit(errcnt);
11580Sstevel@tonic-gate 	}
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 	if ((scanre = calloc(1, sizeof(struct regexp))) == NULL) {
11610Sstevel@tonic-gate 		error(gettext("out of memory"));
11620Sstevel@tonic-gate 		exit(errcnt);
11630Sstevel@tonic-gate 	}
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 	if ((subre = calloc(1, sizeof(struct regexp))) == NULL) {
11660Sstevel@tonic-gate 		error(gettext("out of memory"));
11670Sstevel@tonic-gate 		exit(errcnt);
11680Sstevel@tonic-gate 	}
11690Sstevel@tonic-gate #endif /* XPG4 */
11700Sstevel@tonic-gate }
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate /*
11730Sstevel@tonic-gate  *  Save what is in the special place re to the named alternate
11740Sstevel@tonic-gate  *  location.  This means freeing up what's currently in this target
11750Sstevel@tonic-gate  *  location, if necessary.
11760Sstevel@tonic-gate  */
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate void savere(struct regexp ** a)
11790Sstevel@tonic-gate {
11800Sstevel@tonic-gate #ifdef XPG4
11810Sstevel@tonic-gate 	if (a == NULL || re == NULL) {
11820Sstevel@tonic-gate 		return;
11830Sstevel@tonic-gate 	}
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 	if (*a == NULL) {
11860Sstevel@tonic-gate 		*a = re;
11870Sstevel@tonic-gate 		return;
11880Sstevel@tonic-gate 	}
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 	if (*a != re) {
11910Sstevel@tonic-gate 		if (scanre != subre) {
11920Sstevel@tonic-gate 			regex_comp_free(&((*a)->Expbuf));
11930Sstevel@tonic-gate 			free(*a);
11940Sstevel@tonic-gate 		}
11950Sstevel@tonic-gate 		*a = re;
11960Sstevel@tonic-gate 	}
11970Sstevel@tonic-gate #else /* !XPG4 */
11980Sstevel@tonic-gate 	memcpy(*a, re, sizeof(struct regexp));
11990Sstevel@tonic-gate #endif /* XPG4 */
12000Sstevel@tonic-gate }
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate /*
12040Sstevel@tonic-gate  *  Restore what is in the named alternate location to the special place
12050Sstevel@tonic-gate  *  re.  This means first freeing up what's currently in re, if necessary.
12060Sstevel@tonic-gate  */
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate void resre(struct regexp * a)
12090Sstevel@tonic-gate {
12100Sstevel@tonic-gate #ifdef XPG4
12110Sstevel@tonic-gate 	if (a == NULL) {
12120Sstevel@tonic-gate 		return;
12130Sstevel@tonic-gate 	}
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 	if (re == NULL) {
12160Sstevel@tonic-gate 		re = a;
12170Sstevel@tonic-gate 		return;
12180Sstevel@tonic-gate 	}
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 	if (a != re) {
12210Sstevel@tonic-gate 		if ((re != scanre) && (re != subre)) {
12220Sstevel@tonic-gate 			regex_comp_free(&re->Expbuf);
12230Sstevel@tonic-gate 			free(re);
12240Sstevel@tonic-gate 		}
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 		re = a;
12270Sstevel@tonic-gate 	}
12280Sstevel@tonic-gate #else /* !XPG4 */
12290Sstevel@tonic-gate 	memcpy(re, a, sizeof(struct regexp));
12300Sstevel@tonic-gate #endif /* XPG4 */
12310Sstevel@tonic-gate }
1232