ex_re.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/* Copyright (c) 1981 Regents of the University of California */
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.21 */
#include "ex.h"
#include "ex_re.h"
/* from libgen */
char *_compile(const char *, char *, char *, int);
/*
* The compiled-regular-expression storage areas (re, scanre, and subre)
* have been changed into dynamically allocated memory areas, in both the
* Solaris and XPG4 versions.
*
* In the Solaris version, which uses the original libgen(3g) compile()
* and step() calls, these areas are allocated once, and then data are
* copied between them subsequently, as they were in the original
* implementation. This is possible because the compiled information is
* a self-contained block of bits.
*
* In the XPG4 version, the expr:compile.o object is linked in as a
* simulation of these functions using the new regcomp() and regexec()
* functions. The problem here is that the resulting
* compiled-regular-expression data contain pointers to other data, which
* need to be freed, but only when we are quite sure that we are done
* with them - and certainly not before. There was an earlier attempt to
* handle these differences, but that effort was flawed.
*/
extern char getchar();
#ifdef XPG4
void regex_comp_free(void *);
extern size_t regexc_size; /* compile.c: size of regex_comp structure */
#endif /* XPG4 */
/*
* Global, substitute and regular expressions.
* Very similar to ed, with some re extensions and
* confirmed substitute.
*/
global(k)
bool k;
{
unsigned char *gp;
int c;
line *a1;
unsigned char globuf[GBSIZE], *Cwas;
int nlines = lineDOL();
int oinglobal = inglobal;
unsigned char *oglobp = globp;
char multi[MB_LEN_MAX + 1];
wchar_t wc;
int len;
Cwas = Command;
/*
* States of inglobal:
* 0: ordinary - not in a global command.
* 1: text coming from some buffer, not tty.
* 2: like 1, but the source of the buffer is a global command.
* Hence you're only in a global command if inglobal==2. This
* strange sounding convention is historically derived from
* everybody simulating a global command.
*/
if (inglobal==2)
error(value(vi_TERSE) ? gettext("Global within global") :
gettext("Global within global not allowed"));
markDOT();
setall();
nonzero();
if (skipend())
error(value(vi_TERSE) ? gettext("Global needs re") :
gettext("Missing regular expression for global"));
c = getchar();
(void)vi_compile(c, 1);
savere(&scanre);
gp = globuf;
while ((c = peekchar()) != '\n') {
if (!isascii(c)) {
if (c == EOF) {
c = '\n';
ungetchar(c);
goto out;
}
mb_copy:
if ((len = _mbftowc(multi, &wc, getchar, &peekc)) > 0) {
if ((gp + len) >= &globuf[GBSIZE - 2])
error(gettext("Global command too long"));
strncpy(gp, multi, len);
gp += len;
continue;
}
}
(void) getchar();
switch (c) {
case EOF:
c = '\n';
ungetchar(c);
goto out;
case '\\':
c = peekchar();
if (!isascii(c)) {
*gp++ = '\\';
goto mb_copy;
}
(void) getchar();
switch (c) {
case '\\':
ungetchar(c);
break;
case '\n':
break;
default:
*gp++ = '\\';
break;
}
break;
}
*gp++ = c;
if (gp >= &globuf[GBSIZE - 2])
error(gettext("Global command too long"));
}
out:
donewline();
*gp++ = c;
*gp++ = 0;
saveall();
inglobal = 2;
for (a1 = one; a1 <= dol; a1++) {
*a1 &= ~01;
if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k)
*a1 |= 01;
}
#ifdef notdef
/*
* This code is commented out for now. The problem is that we don't
* fix up the undo area the way we should. Basically, I think what has
* to be done is to copy the undo area down (since we shrunk everything)
* and move the various pointers into it down too. I will do this later
* when I have time. (Mark, 10-20-80)
*/
/*
* Special case: g/.../d (avoid n^2 algorithm)
*/
if (globuf[0]=='d' && globuf[1]=='\n' && globuf[2]=='\0') {
gdelete();
return;
}
#endif
if (inopen)
inopen = -1;
/*
* Now for each marked line, set dot there and do the commands.
* Note the n^2 behavior here for lots of lines matching.
* This is really needed: in some cases you could delete lines,
* causing a marked line to be moved before a1 and missed if
* we didn't restart at zero each time.
*/
for (a1 = one; a1 <= dol; a1++) {
if (*a1 & 01) {
*a1 &= ~01;
dot = a1;
globp = globuf;
commands(1, 1);
a1 = zero;
}
}
globp = oglobp;
inglobal = oinglobal;
endline = 1;
Command = Cwas;
netchHAD(nlines);
setlastchar(EOF);
if (inopen) {
ungetchar(EOF);
inopen = 1;
}
}
/*
* gdelete: delete inside a global command. Handles the
* special case g/r.e./d. All lines to be deleted have
* already been marked. Squeeze the remaining lines together.
* Note that other cases such as g/r.e./p, g/r.e./s/r.e.2/rhs/,
* and g/r.e./.,/r.e.2/d are not treated specially. There is no
* good reason for this except the question: where to you draw the line?
*/
gdelete()
{
line *a1, *a2, *a3;
a3 = dol;
/* find first marked line. can skip all before it */
for (a1=zero; (*a1&01)==0; a1++)
if (a1>=a3)
return;
/* copy down unmarked lines, compacting as we go. */
for (a2=a1+1; a2<=a3;) {
if (*a2&01) {
a2++; /* line is marked, skip it */
dot = a1; /* dot left after line deletion */
} else
*a1++ = *a2++; /* unmarked, copy it */
}
dol = a1-1;
if (dot>dol)
dot = dol;
change();
}
bool cflag;
int scount, slines, stotal;
substitute(c)
int c;
{
line *addr;
int n;
int gsubf, hopcount;
gsubf = compsub(c);
if(FIXUNDO)
save12(), undkind = UNDCHANGE;
stotal = 0;
slines = 0;
for (addr = addr1; addr <= addr2; addr++) {
scount = hopcount = 0;
if (dosubcon(0, addr) == 0)
continue;
if (gsubf) {
/*
* The loop can happen from s/\</&/g
* but we don't want to break other, reasonable cases.
*/
hopcount = 0;
while (*loc2) {
if (++hopcount > sizeof linebuf)
error(gettext("substitution loop"));
if (dosubcon(1, addr) == 0)
break;
}
}
if (scount) {
stotal += scount;
slines++;
putmark(addr);
n = append(getsub, addr);
addr += n;
addr2 += n;
}
}
if (stotal == 0 && !inglobal && !cflag)
error(value(vi_TERSE) ? gettext("Fail") :
gettext("Substitute pattern match failed"));
snote(stotal, slines);
return (stotal);
}
compsub(ch)
{
int seof, c, uselastre;
static int gsubf;
static unsigned char remem[RHSSIZE];
static int remflg = -1;
if (!value(vi_EDCOMPATIBLE))
gsubf = cflag = 0;
uselastre = 0;
switch (ch) {
case 's':
(void)skipwh();
seof = getchar();
if (endcmd(seof) || any(seof, "gcr")) {
ungetchar(seof);
goto redo;
}
if (isalpha(seof) || isdigit(seof))
error(value(vi_TERSE) ? gettext("Substitute needs re") :
gettext("Missing regular expression for substitute"));
seof = vi_compile(seof, 1);
uselastre = 1;
comprhs(seof);
gsubf = cflag = 0;
break;
case '~':
uselastre = 1;
/* fall into ... */
case '&':
redo:
if (re == NULL || re->Expbuf[1] == 0)
error(value(vi_TERSE) ? gettext("No previous re") :
gettext("No previous regular expression"));
if (subre == NULL || subre->Expbuf[1] == 0)
error(value(vi_TERSE) ? gettext("No previous substitute re") :
gettext("No previous substitute to repeat"));
break;
}
for (;;) {
c = getchar();
switch (c) {
case 'g':
gsubf = !gsubf;
continue;
case 'c':
cflag = !cflag;
continue;
case 'r':
uselastre = 1;
continue;
default:
ungetchar(c);
setcount();
donewline();
if (uselastre)
savere(&subre);
else
resre(subre);
/*
* The % by itself on the right hand side means
* that the previous value of the right hand side
* should be used. A -1 is used to indicate no
* previously remembered search string.
*/
if (rhsbuf[0] == '%' && rhsbuf[1] == 0)
if (remflg == -1)
error(gettext("No previously remembered string"));
else
strcpy(rhsbuf, remem);
else {
strcpy(remem, rhsbuf);
remflg = 1;
}
return (gsubf);
}
}
}
comprhs(seof)
int seof;
{
unsigned char *rp, *orp;
int c;
unsigned char orhsbuf[RHSSIZE];
char multi[MB_LEN_MAX + 1];
int len;
wchar_t wc;
rp = rhsbuf;
CP(orhsbuf, rp);
for (;;) {
c = peekchar();
if (c == seof) {
(void) getchar();
break;
}
if (!isascii(c) && c != EOF) {
if ((len = _mbftowc(multi, &wc, getchar, &peekc)) > 0) {
if ((rp + len) >= &rhsbuf[RHSSIZE - 1])
goto toobig;
strncpy(rp, multi, len);
rp += len;
continue;
}
}
(void) getchar();
switch (c) {
case '\\':
c = peekchar();
if (c == EOF) {
(void) getchar();
error(gettext("Replacement string ends with \\"));
}
if (!isascii(c)) {
*rp++ = '\\';
if ((len = _mbftowc(multi, &wc, getchar, &peekc)) > 0) {
if ((rp + len) >= &rhsbuf[RHSSIZE - 1])
goto over_flow;
strncpy(rp, multi, len);
rp += len;
continue;
}
}
(void) getchar();
if (value(vi_MAGIC)) {
/*
* When "magic", \& turns into a plain &,
* and all other chars work fine quoted.
*/
if (c != '&') {
if(rp >= &rhsbuf[RHSSIZE - 1]) {
*rp=0;
error(value(vi_TERSE) ?
gettext("Replacement pattern too long") :
gettext("Replacement pattern too long - limit 256 characters"));
}
*rp++ = '\\';
}
break;
}
magic:
if (c == '~') {
for (orp = orhsbuf; *orp; *rp++ = *orp++)
if (rp >= &rhsbuf[RHSSIZE - 1])
goto toobig;
continue;
}
if(rp >= &rhsbuf[RHSSIZE - 1]) {
over_flow:
*rp=0;
error(value(vi_TERSE) ?
gettext("Replacement pattern too long") :
gettext("Replacement pattern too long - limit 256 characters"));
}
*rp++ = '\\';
break;
case '\n':
case EOF:
if (!(globp && globp[0])) {
ungetchar(c);
goto endrhs;
}
case '~':
case '&':
if (value(vi_MAGIC))
goto magic;
break;
}
if (rp >= &rhsbuf[RHSSIZE - 1]) {
toobig:
*rp = 0;
error(value(vi_TERSE) ?
gettext("Replacement pattern too long") :
gettext("Replacement pattern too long - limit 256 characters"));
}
*rp++ = c;
}
endrhs:
*rp++ = 0;
}
getsub()
{
unsigned char *p;
if ((p = linebp) == 0)
return (EOF);
strcLIN(p);
linebp = 0;
return (0);
}
dosubcon(f, a)
bool f;
line *a;
{
if (execute(f, a) == 0)
return (0);
if (confirmed(a)) {
dosub();
scount++;
}
return (1);
}
confirmed(a)
line *a;
{
int c, cnt, ch;
if (cflag == 0)
return (1);
pofix();
pline(lineno(a));
if (inopen)
putchar('\n' | QUOTE);
c = lcolumn(loc1);
ugo(c, ' ');
ugo(lcolumn(loc2) - c, '^');
flush();
cnt = 0;
bkup:
ch = c = getkey();
again:
if (c == '\b') {
if ((inopen)
&& (cnt > 0)) {
putchar('\b' | QUOTE);
putchar(' ');
putchar('\b' | QUOTE), flush();
cnt --;
}
goto bkup;
}
if (c == '\r')
c = '\n';
if (inopen && MB_CUR_MAX == 1 || c < 0200) {
putchar(c);
flush();
cnt++;
}
if (c != '\n' && c != EOF) {
c = getkey();
goto again;
}
noteinp();
return (ch == 'y');
}
ugo(cnt, with)
int with;
int cnt;
{
if (cnt > 0)
do
putchar(with);
while (--cnt > 0);
}
int casecnt;
bool destuc;
dosub()
{
unsigned char *lp, *sp, *rp;
int c;
int len;
lp = linebuf;
sp = genbuf;
rp = rhsbuf;
while (lp < (unsigned char *)loc1)
*sp++ = *lp++;
casecnt = 0;
/*
* Caution: depending on the hardware, c will be either sign
* extended or not if C&QUOTE is set. Thus, on a VAX, c will
* be < 0, but on a 3B, c will be >= 128.
*/
while (c = *rp) {
if ((len = mblen((char *)rp, MB_CUR_MAX)) <= 0)
len = 1;
/* ^V <return> from vi to split lines */
if (c == '\r')
c = '\n';
if (c == '\\') {
rp++;
if ((len = mblen((char *)rp, MB_CUR_MAX)) <= 0)
len = 1;
switch (c = *rp++) {
case '&':
sp = place(sp, loc1, loc2);
if (sp == 0)
goto ovflo;
continue;
case 'l':
casecnt = 1;
destuc = 0;
continue;
case 'L':
casecnt = LBSIZE;
destuc = 0;
continue;
case 'u':
casecnt = 1;
destuc = 1;
continue;
case 'U':
casecnt = LBSIZE;
destuc = 1;
continue;
case 'E':
case 'e':
casecnt = 0;
continue;
}
if(re != NULL && c >= '1' && c < re->Nbra + '1') {
sp = place(sp, braslist[c - '1'] , braelist[c - '1']);
if (sp == 0)
goto ovflo;
continue;
}
rp--;
}
if (len > 1) {
if ((sp + len) >= &genbuf[LBSIZE])
goto ovflo;
strncpy(sp, rp, len);
} else {
if (casecnt)
*sp = fixcase(c);
else
*sp = c;
}
sp += len; rp += len;
if (sp >= &genbuf[LBSIZE])
ovflo:
error(value(vi_TERSE) ? gettext("Line overflow") :
gettext("Line overflow in substitute"));
}
lp = (unsigned char *)loc2;
loc2 = (char *)(linebuf + (sp - genbuf));
while (*sp++ = *lp++)
if (sp >= &genbuf[LBSIZE])
goto ovflo;
strcLIN(genbuf);
}
fixcase(c)
int c;
{
if (casecnt == 0)
return (c);
casecnt--;
if (destuc) {
if (islower(c))
c = toupper(c);
} else
if (isupper(c))
c = tolower(c);
return (c);
}
unsigned char *
place(sp, l1, l2)
unsigned char *sp, *l1, *l2;
{
while (l1 < l2) {
*sp++ = fixcase(*l1++);
if (sp >= &genbuf[LBSIZE])
return (0);
}
return (sp);
}
snote(total, nlines)
int total, nlines;
{
if (!notable(total))
return;
if (nlines != 1 && nlines != total)
printf(mesg(value(vi_TERSE) ?
/*
* TRANSLATION_NOTE
* Reference order of arguments must not
* be changed using '%digit$', since vi's
* printf() does not support it.
*/
gettext("%d subs on %d lines") :
/*
* TRANSLATION_NOTE
* Reference order of arguments must not
* be changed using '%digit$', since vi's
* printf() does not support it.
*/
gettext("%d substitutions on %d lines")),
total, nlines);
else
printf(mesg(value(vi_TERSE) ?
gettext("%d subs") :
gettext("%d substitutions")),
total);
noonl();
flush();
}
#ifdef XPG4
#include <regex.h>
extern int regcomp_flags; /* use to specify cflags for regcomp() */
#endif /* XPG4 */
vi_compile(eof, oknl)
int eof;
int oknl;
{
int c;
unsigned char *gp, *p1;
unsigned char *rhsp;
unsigned char rebuf[LBSIZE];
char multi[MB_LEN_MAX + 1];
int len;
wchar_t wc;
#ifdef XPG4
/*
* reset cflags to plain BRE
* if \< and/or \> is specified, REG_WORDS is set.
*/
regcomp_flags = 0;
#endif /* XPG4 */
gp = genbuf;
if (isalpha(eof) || isdigit(eof))
error(gettext("Regular expressions cannot be delimited by letters or digits"));
if(eof >= 0200 && MB_CUR_MAX > 1)
error(gettext("Regular expressions cannot be delimited by multibyte characters"));
c = getchar();
if (eof == '\\')
switch (c) {
case '/':
case '?':
if (scanre == NULL || scanre->Expbuf[1] == 0)
error(value(vi_TERSE) ? gettext("No previous scan re") :
gettext("No previous scanning regular expression"));
resre(scanre);
return (c);
case '&':
if (subre == NULL || subre->Expbuf[1] == 0)
error(value(vi_TERSE) ? gettext("No previous substitute re") :
gettext("No previous substitute regular expression"));
resre(subre);
return (c);
default:
error(value(vi_TERSE) ? gettext("Badly formed re") :
gettext("Regular expression \\ must be followed by / or ?"));
}
if (c == eof || c == '\n' || c == EOF) {
if (re == NULL || re->Expbuf[1] == 0)
error(value(vi_TERSE) ? gettext("No previous re") :
gettext("No previous regular expression"));
if (c == '\n' && oknl == 0)
error(value(vi_TERSE) ? gettext("Missing closing delimiter") :
gettext("Missing closing delimiter for regular expression"));
if (c != eof)
ungetchar(c);
return (eof);
}
gp = genbuf;
if (c == '^') {
*gp++ = c;
c = getchar();
}
ungetchar(c);
for (;;) {
c = getchar();
if (c == eof || c == EOF) {
if (c == EOF)
ungetchar(c);
goto out;
}
if (gp >= &genbuf[LBSIZE - 3])
complex:
cerror(value(vi_TERSE) ? gettext("Re too complex") :
gettext("Regular expression too complicated"));
if (!(isascii(c) || MB_CUR_MAX == 1)) {
ungetchar(c);
if ((len = _mbftowc(multi, &wc, getchar, &peekc)) >= 1) {
if ((gp + len) >= &genbuf[LBSIZE - 3])
goto complex;
strncpy(gp, multi, len);
gp += len;
continue;
}
(void) getchar();
}
switch (c) {
case '\\':
c = getchar();
if (!isascii(c)) {
ungetchar(c);
if ((len = _mbftowc(multi, &wc, getchar, &peekc)) >= 1) {
if ((gp + len) >= &genbuf[LBSIZE - 3])
goto complex;
*gp++ = '\\';
strncpy(gp, multi, len);
gp += len;
continue;
}
(void) getchar();
}
switch (c) {
case '<':
case '>':
#ifdef XPG4
regcomp_flags = REG_WORDS;
/*FALLTHRU*/
#endif /* XPG4 */
case '(':
case ')':
case '{':
case '}':
case '$':
case '^':
case '\\':
*gp++ = '\\';
*gp++ = c;
continue;
case 'n':
*gp++ = c;
continue;
}
if(c >= '0' && c <= '9') {
*gp++ = '\\';
*gp++ = c;
continue;
}
if (value(vi_MAGIC) == 0)
magic:
switch (c) {
case '.':
*gp++ = '.';
continue;
case '~':
rhsp = rhsbuf;
while (*rhsp) {
if (!isascii(*rhsp)) {
if ((len = mbtowc((wchar_t *)0, (char *)rhsp, MB_CUR_MAX)) > 1) {
if ((gp + len) >= &genbuf[LBSIZE-2])
goto complex;
strncpy(gp, rhsp, len);
rhsp += len; gp += len;
continue;
}
}
len = 1;
if (*rhsp == '\\') {
c = *++rhsp;
if (c == '&')
cerror(value(vi_TERSE) ? gettext("Replacement pattern contains &") :
gettext("Replacement pattern contains & - cannot use in re"));
if (c >= '1' && c <= '9')
cerror(value(vi_TERSE) ? gettext("Replacement pattern contains \\d") :
gettext("Replacement pattern contains \\d - cannot use in re"));
if ((len = mbtowc((wchar_t *)0, (char *)rhsp, MB_CUR_MAX)) <= 1) {
len = 1;
if(any(c, ".\\*[$"))
*gp++ = '\\';
}
}
if ((gp + len) >= &genbuf[LBSIZE-2])
goto complex;
if (len == 1) {
c = *rhsp++;
*gp++ = (value(vi_IGNORECASE) ? tolower(c) : c);
} else {
strncpy(gp, rhsp, len);
gp += len; rhsp += len;
}
}
continue;
case '*':
*gp++ = '*';
continue;
case '[':
*gp++ = '[';
c = getchar();
if (c == '^') {
*gp++ = '^';
c = getchar();
}
do {
if (!isascii(c) && c != EOF) {
ungetchar(c);
if ((len = _mbftowc(multi, &wc, getchar, &peekc)) >= 1) {
if ((gp + len)>= &genbuf[LBSIZE-4])
goto complex;
strncpy(gp, multi, len);
gp += len;
c = getchar();
continue;
}
(void) getchar();
}
if (gp >= &genbuf[LBSIZE-4])
goto complex;
if(c == '\\' && peekchar() == ']') {
(void)getchar();
*gp++ = '\\';
*gp++ = ']';
}
else if (c == '\n' || c == EOF)
cerror(gettext("Missing ]"));
else
*gp++ = (value(vi_IGNORECASE) ? tolower(c) : c);
c = getchar();
} while(c != ']');
*gp++ = ']';
continue;
}
if (c == EOF) {
ungetchar(EOF);
*gp++ = '\\';
*gp++ = '\\';
continue;
}
if (c == '\n')
cerror(value(vi_TERSE) ? gettext("No newlines in re's") :
gettext("Can't escape newlines into regular expressions"));
*gp++ = '\\';
*gp++ = (value(vi_IGNORECASE) ? tolower(c) : c);
continue;
case '\n':
if (oknl) {
ungetchar(c);
goto out;
}
cerror(value(vi_TERSE) ? gettext("Badly formed re") :
gettext("Missing closing delimiter for regular expression"));
case '.':
case '~':
case '*':
case '[':
if (value(vi_MAGIC))
goto magic;
if(c != '~')
*gp++ = '\\';
defchar:
default:
*gp++ = (value(vi_IGNORECASE) ? tolower(c) : c);
continue;
}
}
out:
*gp++ = '\0';
#ifdef XPG4
/* see if our compiled RE's will fit in the re structure: */
if (regexc_size > EXPSIZ) {
/*
* this should never happen. but it's critical that we
* check here, otherwise .bss would get overwritten.
*/
cerror(value(vi_TERSE) ? gettext("RE's can't fit") :
gettext("Regular expressions can't fit"));
return(eof);
}
/*
* We create re each time we need it.
*/
if (re == NULL || re == scanre || re == subre) {
if ((re = calloc(1, sizeof(struct regexp))) == NULL) {
error(gettext("out of memory"));
exit(errcnt);
}
} else {
regex_comp_free(&re->Expbuf);
memset(re, 0, sizeof(struct regexp));
}
compile((char *) genbuf, (char *) re->Expbuf, (char *) re->Expbuf
+ regexc_size);
#else /* !XPG4 */
(void) _compile((const char *)genbuf, (char *)re->Expbuf,
(char *)(re->Expbuf + sizeof (re->Expbuf)), 1);
#endif /* XPG4 */
if(regerrno)
switch(regerrno) {
case 42:
cerror(gettext("\\( \\) Imbalance"));
case 43:
cerror(value(vi_TERSE) ? gettext("Awash in \\('s!") :
gettext("Too many \\('d subexpressions in a regular expression"));
case 50:
goto complex;
case 67:
cerror(value(vi_TERSE) ? gettext("Illegal byte sequence") :
gettext("Regular expression has illegal byte sequence"));
}
re->Nbra = nbra;
return(eof);
}
cerror(s)
unsigned char *s;
{
if (re) {
re->Expbuf[0] = re->Expbuf[1] = 0;
}
error(s);
}
execute(gf, addr)
line *addr;
{
unsigned char *p1, *p2;
char *start;
int c, i;
int ret;
int len;
if (gf) {
if (re == NULL || re->Expbuf[0])
return (0);
if(value(vi_IGNORECASE)) {
p1 = genbuf;
p2 = (unsigned char *)loc2;
while(c = *p2) {
if ((len = mblen((char *)p2, MB_CUR_MAX)) <= 0)
len = 1;
if (len == 1) {
*p1++ = tolower(c);
p2++;
continue;
}
strncpy(p1, p2, len);
p1 += len; p2 += len;
}
*p1 = '\0';
locs = (char *)genbuf;
p1 = genbuf;
start = loc2;
} else {
p1 = (unsigned char *)loc2;
locs = loc2;
}
} else {
if (addr == zero)
return (0);
p1 = linebuf;
getline(*addr);
if(value(vi_IGNORECASE)) {
p1 = genbuf;
p2 = linebuf;
while(c = *p2) {
if ((len = mblen((char *)p2, MB_CUR_MAX)) <= 0)
len = 1;
if (len == 1) {
*p1++ = tolower(c);
p2++;
continue;
}
strncpy(p1, p2, len);
p1 += len; p2 += len;
}
*p1 = '\0';
p1 = genbuf;
start = (char *)linebuf;
}
locs = (char *)0;
}
ret = step((char *)p1, (char *)re->Expbuf);
if(value(vi_IGNORECASE) && ret) {
loc1 = start + (loc1 - (char *)genbuf);
loc2 = start + (loc2 - (char *)genbuf);
for(i = 0; i < NBRA; i++) {
braslist[i] = start + (braslist[i] - (char *)genbuf);
braelist[i] = start + (braelist[i] - (char *)genbuf);
}
}
return ret;
}
/*
* Initialize the compiled regular-expression storage areas (called from
* main()).
*/
void init_re (void)
{
#ifdef XPG4
re = scanre = subre = NULL;
#else /* !XPG4 */
if ((re = calloc(1, sizeof(struct regexp))) == NULL) {
error(gettext("out of memory"));
exit(errcnt);
}
if ((scanre = calloc(1, sizeof(struct regexp))) == NULL) {
error(gettext("out of memory"));
exit(errcnt);
}
if ((subre = calloc(1, sizeof(struct regexp))) == NULL) {
error(gettext("out of memory"));
exit(errcnt);
}
#endif /* XPG4 */
}
/*
* Save what is in the special place re to the named alternate
* location. This means freeing up what's currently in this target
* location, if necessary.
*/
void savere(struct regexp ** a)
{
#ifdef XPG4
if (a == NULL || re == NULL) {
return;
}
if (*a == NULL) {
*a = re;
return;
}
if (*a != re) {
if (scanre != subre) {
regex_comp_free(&((*a)->Expbuf));
free(*a);
}
*a = re;
}
#else /* !XPG4 */
memcpy(*a, re, sizeof(struct regexp));
#endif /* XPG4 */
}
/*
* Restore what is in the named alternate location to the special place
* re. This means first freeing up what's currently in re, if necessary.
*/
void resre(struct regexp * a)
{
#ifdef XPG4
if (a == NULL) {
return;
}
if (re == NULL) {
re = a;
return;
}
if (a != re) {
if ((re != scanre) && (re != subre)) {
regex_comp_free(&re->Expbuf);
free(re);
}
re = a;
}
#else /* !XPG4 */
memcpy(re, a, sizeof(struct regexp));
#endif /* XPG4 */
}