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