/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
* 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 */
#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 int getchar();
#ifdef XPG4
void regex_comp_free(void *);
#endif /* XPG4 */
/*
* Global, substitute and regular expressions.
* Very similar to ed, with some re extensions and
* confirmed substitute.
*/
void
global(k)
bool k;
{
unsigned char *gp;
int c;
int len;
/*
* 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)
gettext("Global within global not allowed"));
markDOT();
setall();
nonzero();
if (skipend())
gettext("Missing regular expression for global"));
c = getchar();
(void)vi_compile(c, 1);
while ((c = peekchar()) != '\n') {
if (!isascii(c)) {
if (c == EOF) {
c = '\n';
ungetchar(c);
goto out;
}
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;
}
out:
donewline();
*gp++ = c;
*gp++ = 0;
saveall();
inglobal = 2;
*a1 &= ~01;
*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)
*/
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.
*/
if (*a1 & 01) {
*a1 &= ~01;
}
}
endline = 1;
if (inopen) {
inopen = 1;
}
}
/*
* gdelete: delete inside a global command. Handles the
* already been marked. Squeeze the remaining lines together.
* good reason for this except the question: where to you draw the line?
*/
void
gdelete(void)
{
/* find first marked line. can skip all before it */
return;
/* copy down unmarked lines, compacting as we go. */
if (*a2&01) {
a2++; /* line is marked, skip it */
} else
}
change();
}
bool cflag;
int
substitute(int c)
{
int n;
if(FIXUNDO)
stotal = 0;
slines = 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) {
break;
}
}
if (scount) {
slines++;
addr += n;
addr2 += n;
}
}
gettext("Substitute pattern match failed"));
return (stotal);
}
int
{
static int gsubf;
if (!value(vi_EDCOMPATIBLE))
uselastre = 0;
switch (ch) {
case 's':
(void)skipwh();
goto redo;
}
gettext("Missing regular expression for substitute"));
uselastre = 1;
break;
case '~':
uselastre = 1;
/* fall into ... */
case '&':
redo:
gettext("No previous regular expression"));
gettext("No previous substitute to repeat"));
break;
}
for (;;) {
c = getchar();
switch (c) {
case 'g':
continue;
case 'c':
continue;
case 'r':
uselastre = 1;
continue;
default:
ungetchar(c);
setcount();
donewline();
if (uselastre)
else
/*
* 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 (remflg == -1)
else
else {
remflg = 1;
}
return (gsubf);
}
}
}
void
{
int c;
int len;
for (;;) {
c = peekchar();
if (c == seof) {
(void) getchar();
break;
}
goto toobig;
continue;
}
}
(void) getchar();
switch (c) {
case '\\':
c = peekchar();
if (c == EOF) {
(void) getchar();
}
if (!isascii(c)) {
*rp++ = '\\';
goto over_flow;
continue;
}
}
(void) getchar();
/*
* When "magic", \& turns into a plain &,
* and all other chars work fine quoted.
*/
if (c != '&') {
*rp=0;
gettext("Replacement pattern too long") :
gettext("Replacement pattern too long - limit 256 characters"));
}
*rp++ = '\\';
}
break;
}
if (c == '~') {
goto toobig;
continue;
}
*rp=0;
gettext("Replacement pattern too long") :
gettext("Replacement pattern too long - limit 256 characters"));
}
*rp++ = '\\';
break;
case '\n':
case EOF:
ungetchar(c);
goto endrhs;
}
case '~':
case '&':
goto magic;
break;
}
*rp = 0;
gettext("Replacement pattern too long") :
gettext("Replacement pattern too long - limit 256 characters"));
}
*rp++ = c;
}
*rp++ = 0;
}
int
getsub(void)
{
unsigned char *p;
if ((p = linebp) == 0)
return (EOF);
strcLIN(p);
linebp = 0;
return (0);
}
int
{
if (execute(f, a) == 0)
return (0);
if (confirmed(a)) {
dosub();
scount++;
}
return (1);
}
int
{
if (cflag == 0)
return (1);
pofix();
if (inopen)
ugo(c, ' ');
flush();
cnt = 0;
bkup:
if (c == '\b') {
if ((inopen)
&& (cnt > 0)) {
putchar(' ');
cnt --;
}
goto bkup;
}
if (c == '\r')
c = '\n';
putchar(c);
flush();
cnt++;
}
if (c != '\n' && c != EOF) {
c = getkey();
goto again;
}
noteinp();
return (ch == 'y');
}
void
{
if (cnt > 0)
do
while (--cnt > 0);
}
int casecnt;
bool destuc;
void
dosub(void)
{
int c;
int len;
casecnt = 0;
/*
* Caution: depending on the hardware, c will be either sign
* extended or not if C"E is set. Thus, on a VAX, c will
* be < 0, but on a 3B, c will be >= 128.
*/
while (c = *rp) {
len = 1;
/* ^V <return> from vi to split lines */
if (c == '\r')
c = '\n';
if (c == '\\') {
rp++;
len = 1;
switch (c = *rp++) {
case '&':
if (sp == 0)
goto ovflo;
continue;
case 'l':
casecnt = 1;
destuc = 0;
continue;
case 'L':
destuc = 0;
continue;
case 'u':
casecnt = 1;
destuc = 1;
continue;
case 'U':
destuc = 1;
continue;
case 'E':
case 'e':
casecnt = 0;
continue;
}
if (sp == 0)
goto ovflo;
continue;
}
rp--;
}
if (len > 1) {
goto ovflo;
} else {
if (casecnt)
else
*sp = c;
}
gettext("Line overflow in substitute"));
}
goto ovflo;
}
int
fixcase(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 *
{
return (0);
}
return (sp);
}
void
{
return;
/*
* TRANSLATION_NOTE
* Reference order of arguments must not
* be changed using '%digit$', since vi's
* viprintf() 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
* viprintf() does not support it.
*/
gettext("%d substitutions on %d lines")),
else
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 */
int
{
int c;
unsigned char *rhsp;
int len;
#ifdef XPG4
/*
* reset cflags to plain BRE
*/
regcomp_flags = 0;
#endif /* XPG4 */
c = getchar();
if (eof == '\\')
switch (c) {
case '/':
case '?':
gettext("No previous scanning regular expression"));
return (c);
case '&':
gettext("No previous substitute regular expression"));
return (c);
default:
gettext("Regular expression \\ must be followed by / or ?"));
}
gettext("No previous regular expression"));
if (c == '\n' && oknl == 0)
gettext("Missing closing delimiter for regular expression"));
if (c != eof)
ungetchar(c);
return (eof);
}
if (c == '^') {
*gp++ = c;
c = getchar();
}
ungetchar(c);
for (;;) {
c = getchar();
if (c == EOF)
ungetchar(c);
goto out;
}
(unsigned char *)gettext("Re too complex") :
(unsigned char *)
gettext("Regular expression too complicated"));
ungetchar(c);
goto complex;
continue;
}
(void) getchar();
}
switch (c) {
case '\\':
c = getchar();
if (!isascii(c)) {
ungetchar(c);
goto complex;
*gp++ = '\\';
continue;
}
(void) getchar();
}
switch (c) {
case '<':
case '>':
#ifdef XPG4
/*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;
}
switch (c) {
case '.':
*gp++ = '.';
continue;
case '~':
while (*rhsp) {
goto complex;
continue;
}
}
len = 1;
if (*rhsp == '\\') {
c = *++rhsp;
if (c == '&')
gettext("Replacement pattern contains &") :
(unsigned char *)gettext("Replacement pattern contains & - cannot use in re"));
if (c >= '1' && c <= '9')
gettext("Replacement pattern contains \\d") :
(unsigned char *)
gettext("Replacement pattern contains \\d - cannot use in re"));
len = 1;
if(any(c, ".\\*[$"))
*gp++ = '\\';
}
}
goto complex;
if (len == 1) {
c = *rhsp++;
} else {
}
}
continue;
case '*':
*gp++ = '*';
continue;
case '[':
*gp++ = '[';
c = getchar();
if (c == '^') {
*gp++ = '^';
c = getchar();
}
do {
ungetchar(c);
goto complex;
c = getchar();
continue;
}
(void) getchar();
}
goto complex;
(void)getchar();
*gp++ = '\\';
*gp++ = ']';
}
else if (c == '\n' || c == EOF)
cerror((unsigned char *)
gettext("Missing ]"));
else
c = getchar();
} while(c != ']');
*gp++ = ']';
continue;
}
if (c == EOF) {
*gp++ = '\\';
*gp++ = '\\';
continue;
}
if (c == '\n')
(unsigned char *)gettext("Can't escape newlines into regular expressions"));
*gp++ = '\\';
continue;
case '\n':
if (oknl) {
ungetchar(c);
goto out;
}
(unsigned char *)gettext("Missing closing delimiter for regular expression"));
case '.':
case '~':
case '*':
case '[':
goto magic;
if(c != '~')
*gp++ = '\\';
default:
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.
*/
gettext("RE's can't fit") :
(unsigned char *)gettext("Regular expressions can't fit"));
return(eof);
}
/*
* We create re each time we need it.
*/
}
} else {
}
+ regexc_size);
#else /* !XPG4 */
#endif /* XPG4 */
if(regerrno)
switch(regerrno) {
case 42:
case 43:
(unsigned char *)
gettext("Too many \\('d subexpressions in a regular expression"));
case 50:
goto complex;
case 67:
(unsigned char *)gettext("Regular expression has illegal byte sequence"));
}
return(eof);
}
void
cerror(unsigned char *s)
{
if (re) {
}
error(s);
}
int
{
char *start;
int c, i;
int ret;
int len;
if (gf) {
return (0);
if(value(vi_IGNORECASE)) {
while(c = *p2) {
len = 1;
if (len == 1) {
p2++;
continue;
}
}
*p1 = '\0';
} else {
}
} else {
return (0);
if(value(vi_IGNORECASE)) {
while(c = *p2) {
len = 1;
if (len == 1) {
p2++;
continue;
}
}
*p1 = '\0';
}
locs = (char *)0;
}
for(i = 0; i < NBRA; i++) {
}
}
return ret;
}
/*
* Initialize the compiled regular-expression storage areas (called from
* main()).
*/
void init_re (void)
{
#ifdef XPG4
#else /* !XPG4 */
}
}
}
#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.
*/
{
#ifdef XPG4
return;
}
if (*a == NULL) {
*a = re;
return;
}
if (*a != re) {
regex_comp_free(&((*a)->Expbuf));
free(*a);
}
*a = re;
}
#else /* !XPG4 */
#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.
*/
{
#ifdef XPG4
if (a == NULL) {
return;
}
re = a;
return;
}
if (a != re) {
}
re = a;
}
#else /* !XPG4 */
#endif /* XPG4 */
}