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"E 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