/* * This code contains changes by * Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved. * * Conditions 1, 2, and 4 and the no-warranty notice below apply * to these changes. * * * Copyright (c) 1980, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * Redistributions of source code and documentation must retain the * above copyright notice, this list of conditions and the following * disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of * other contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef lint #ifdef DOSCCS static char sccsid[] = "@(#)ex_re.c 1.56 (gritter) 3/25/05"; #endif #endif /* from ex_re.c 7.5 (Berkeley) 6/7/85 */ #include "ex.h" #include "ex_re.h" #ifdef UXRE #include char *braslist[NBRA]; char *braelist[NBRA]; char *loc1; char *loc2; #else /* !UXRE */ static int regerrno; #define INIT register char *sp = instring; #define GETC() (*sp++) #define PEEKC() (*sp) #define UNGETC(c) (--sp) #define RETURN(c) return(ep); #define ERROR(c) { regerrno = c; return 0; } #define compile(a, b, c, d) _compile(a, b, c, d) #define regexp_h_static static #ifndef NO_BE_BACKSLASH #define REGEXP_H_VI_BACKSLASH #endif /* !NO_BE_BACKSLASH */ #ifdef MB #define REGEXP_H_WCHARS #endif /* MB */ #define REGEXP_H_USED_FROM_VI #include "regexp.h" #ifndef REG_ICASE #define REG_ICASE 1 #endif static size_t loconv(register char *dst, register const char *src) { char *odst = dst; #ifdef MB if (mb_cur_max > 1) { char mb[MB_LEN_MAX]; wchar_t wc; int len, i, nlen; for (;;) { if ((*src & 0200) == 0) { *dst++ = tolower(*src); if (*src++ == '\0') break; } else if ((len = mbtowc(&wc, src, mb_cur_max)) <= 0) { *dst++ = *src++; } else { wc = towlower(wc); if (len >= mb_cur_max) { if ((nlen = wctomb(dst, wc)) <= len) { dst += nlen; src += len; } else { *dst++ = *src++; } } else { if ((nlen = wctomb(mb, wc)) <= len) { src += len; for (i = 0; i < nlen; i++) *dst++ = mb[i]; } else { *dst++ = *src++; } } } } } else #endif /* MB */ { do *dst++ = tolower(*src & 0377); while (*src++); } return dst - odst; } #undef compile #endif /* !UXRE */ /* * Global, substitute and regular expressions. * Very similar to ed, with some re extensions and * confirmed substitute. */ void global(int k) { register char *gp; register int c, i; register line *a1; char mb[MB_LEN_MAX+1]; char globuf[GBSIZE], *Cwas; int lines = lineDOL(); int oinglobal = inglobal; char *oglobp = globp; 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(catgets(catd, 1, 121, "Global within global@not allowed")); markDOT(); setall(); nonzero(); if (skipend()) error(catgets(catd, 1, 122, "Global needs re|Missing regular expression for global")); c = GETWC(mb); ignore(compile(c, 1)); savere(&scanre); gp = globuf; while ((c = GETWC(mb)) != '\n') { switch (c) { case EOF: c = '\n'; goto brkwh; case '\\': c = GETWC(mb); switch (c) { case '\\': ungetchar(c); break; case '\n': break; default: *gp++ = '\\'; break; } break; } for (i = 0; mb[i]; i++) { *gp++ = mb[i]; if (gp >= &globuf[GBSIZE - 2]) error(catgets(catd, 1, 123, "Global command too long")); } } brkwh: ungetchar(c); /* out: */ newline(); *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(lines); 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? */ void gdelete(void) { register 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; int substitute(int c) { register line *addr; register 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/\ sizeof linebuf) error(catgets(catd, 1, 124, "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(catgets(catd, 1, 125, "Fail|Substitute pattern match failed")); snote(stotal, slines); return (stotal); } int compsub(int ch) { register int seof, c, uselastre; char mb[MB_LEN_MAX+1]; static int gsubf; if (!value(EDCOMPATIBLE)) gsubf = cflag = 0; uselastre = 0; switch (ch) { case 's': ignore(skipwh()); seof = GETWC(mb); if (endcmd(seof) || any(seof, "gcr")) { ungetchar(seof); goto redo; } if (xisalnum(seof)) error(catgets(catd, 1, 126, "Substitute needs re|Missing regular expression for substitute")); seof = compile(seof, 1); uselastre = 1; comprhs(seof); gsubf = 0; cflag = 0; break; case '~': uselastre = 1; /* fall into ... */ case '&': redo: if (re.Patbuf[0] == 0) error(catgets(catd, 1, 127, "No previous re|No previous regular expression")); if (subre.Patbuf[0] == 0) error(catgets(catd, 1, 128, "No previous substitute re|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(); newline(); if (uselastre) savere(&subre); else resre(&subre); return (gsubf); } } } void comprhs(int seof) { register char *rp, *orp; char mb[MB_LEN_MAX+1]; #ifdef BIT8 char *qp, *oqp; #endif register int c, i; #ifdef BIT8 int q; #endif char orhsbuf[RHSSIZE]; #ifdef BIT8 char orhsquo[RHSSIZE]; #endif int hashflag = 0; rp = rhsbuf; #ifdef BIT8 qp = rhsquo; #endif CP(orhsbuf, rp); #ifdef BIT8 copy(orhsquo, qp, (size_t) strlen(rp)); #endif for (;;) { c = GETWC(mb); #ifdef BIT8 q = 0; #endif if (c == seof) break; switch (c) { case '%': if (rp == rhsbuf) hashflag = 1; break; case '\\': c = GETWC(mb); if (c == EOF) { ungetchar(c); break; } if (value(MAGIC)) { /* * When "magic", \& turns into a plain &, * and all other chars work fine quoted. */ if (c != '&') #ifndef BIT8 c |= QUOTE; #else q = 1; #endif break; } magic: if (c == '~') { hash: #ifndef BIT8 for (orp = orhsbuf; *orp; *rp++ = *orp++) { #else for (orp = orhsbuf, oqp = orhsquo; *orp; *rp++ = *orp++) { *qp++ = *oqp++; #endif if (rp >= &rhsbuf[RHSSIZE - 1]) goto toobig; } if (hashflag & 2) goto endrhs; continue; } #ifndef BIT8 c |= QUOTE; #else q = 1; #endif break; case '\n': case EOF: if (!(globp && globp[0])) { ungetchar(c); goto endrhs; } case '~': case '&': if (value(MAGIC)) goto magic; break; } if (rp >= &rhsbuf[RHSSIZE - 1]) { toobig: *rp = 0; error(catgets(catd, 1, 129, "Replacement pattern too long@- limit 256 characters")); } for (i = 0; mb[i]; i++) { *rp++ = mb[i]; #ifdef BIT8 *qp++ = q; #endif } } endrhs: if (hashflag == 1 && rhsbuf[0] == '%' && rp == &rhsbuf[1]) { rp = rhsbuf; hashflag |= 2; goto hash; } *rp++ = 0; } int getsub(void) { register char *p; if ((p = linebp) == 0) return (EOF); strcLIN(p); linebp = 0; return (0); } int dosubcon(bool f, line *a) { if (execute(f, a) == 0) return (0); if (confirmed(a)) { dosub(); scount++; } return (1); } int confirmed(line *a) { register int c; char *yesstr = catgets(catd, 1, 249, "y"); int okay = -1; if (cflag == 0) return (1); pofix(); pline(lineno(a)); if (inopen) putchar('\n' | QUOTE); c = column(loc1 - 1); ugo(c - 1 + (inopen ? 1 : 0), ' '); ugo(column(loc2 - 1) - c, '^'); flush(); c = getkey(); again: if (c == '\r') c = '\n'; if (inopen) putchar(c), flush(); if (c != '\n' && c != EOF) { if (okay && *yesstr) { if (c == (*yesstr++ & 0377)) okay = 1; else okay = 0; } c = getkey(); goto again; } noteinp(); return (okay > 0); } #ifdef notdef int ex_getch(void) { char c; if (read(2, &c, 1) != 1) return (EOF); #ifndef BIT8 return (c & TRIM); #else return c; #endif } #endif /* notdef */ void ugo(int cnt, int with) { if (cnt > 0) do putchar(with); while (--cnt > 0); } int casecnt; bool destuc; void dosub(void) { register char *lp, *sp, *rp; int c, n; #ifdef BIT8 register char *qp; int q; #endif lp = linebuf; sp = genbuf; rp = rhsbuf; #ifdef BIT8 qp = rhsquo; #endif while (lp < loc1) *sp++ = *lp++; casecnt = 0; while (*rp) { nextc(c, rp, n); rp += n; #ifdef BIT8 c &= TRIM; q = *qp; qp += n; #endif /* ^V from vi to split lines */ if (c == '\r') c = '\n'; #ifndef BIT8 if (c & QUOTE) switch (c & TRIM) { #else if (q) switch (c) { #endif 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; } #ifndef BIT8 if (c < 0 && (c &= TRIM) >= '1' && c < re.Nbra + '1') { #else if (q && c >= '1' && c < re.Nbra + '1') { #endif sp = place(sp, braslist[c - '1'], braelist[c - '1']); if (sp == 0) goto ovflo; continue; } #ifdef MB if (mb_cur_max > 1) { char mb[MB_LEN_MAX+1]; int i, m; if (casecnt) c = fixcase(c & TRIM); if (c & INVBIT || (m = wctomb(mb, c)) <= 0) { mb[0] = rp[-n]; m = 1; } for (i = 0; i < m; i++) { *sp++ = mb[i]; if (sp >= &genbuf[LBSIZE]) goto ovflo; } } else #endif /* MB */ { if (casecnt) *sp++ = fixcase(c & TRIM); else *sp++ = c & TRIM; } if (sp >= &genbuf[LBSIZE]) ovflo: error(catgets(catd, 1, 130, "Line overflow@in substitute")); } lp = loc2; loc2 = sp + (linebuf - genbuf); #ifdef UXRE if (loc1 == lp) { nextc(c, loc2, n); loc2 += n; } #endif /* UXRE */ while (*sp++ = *lp++) if (sp >= &genbuf[LBSIZE]) goto ovflo; strcLIN(genbuf); } int fixcase(register int c) { if (casecnt == 0) return (c); casecnt--; #ifdef MB if (c & INVBIT) return (c); if (mb_cur_max > 1) { if (destuc) { if (iswlower(c)) c = towupper(c); } else if (iswupper(c)) c = towlower(c); } else #endif /* MB */ { if (destuc) { if (islower(c)) c = toupper(c); } else if (isupper(c)) c = tolower(c); } return (c); } char * place(register char *sp, register char *l1, register char *l2) { while (l1 < l2) { #ifdef MB if (mb_cur_max > 1) { char mb[MB_LEN_MAX+1]; int c, i, m, n; nextc(c, l1, m); if (c & INVBIT) { m = n = 1; *mb = *l1; } else { c = fixcase(c); if ((n = wctomb(mb, c)) <= 0) { n = 1; *mb = *l1; } } l1 += m; for (i = 0; i < n; i++) { *sp++ = mb[i]; if (sp >= &genbuf[LBSIZE]) return (0); } } else #endif /* MB */ { *sp++ = fixcase(*l1++); if (sp >= &genbuf[LBSIZE]) return (0); } } return (sp); } void snote(register int total, register int lines) { if (!notable(total)) return; printf(mesg(catgets(catd, 1, 131, "%d subs|%d substitutions")), total); if (lines != 1 && lines != total) printf(catgets(catd, 1, 132, " on %d lines"), lines); noonl(); flush(); } void cerror(char *s) { re.Patbuf[0] = '\0'; error(s); } void refree(struct regexp *rp) { struct regexp *r1 = NULL, *r2 = NULL; if (rp->Expbuf == 0) return; if (rp == &re) { r1 = &scanre; r2 = &subre; } else if (rp == &scanre) { r1 = &re; r2 = &subre; } else if (rp == &subre) { r1 = &re; r2 = &scanre; } if ((r1->Expbuf == 0 || rp->Re_ident != r1->Re_ident) && (r2->Expbuf == 0 || rp->Re_ident != r2->Re_ident)) { #ifdef UXRE regfree(rp->Expbuf); #endif /* UXRE */ free(rp->Expbuf); } rp->Expbuf = 0; } struct regexp * savere(struct regexp *store) { refree(store); copy(store, &re, sizeof re); return store; } struct regexp * resre(struct regexp *store) { refree(&re); copy(&re, store, sizeof re); return store; } static void compile1(void) { #ifdef UXRE int n; #else /* !UXRE */ char *r; char *p; #endif /* !UXRE */ refree(&re); re.Flags = value(IGNORECASE) ? REG_ICASE : 0; #ifdef UXRE re.Flags |= REG_ANGLES; #ifndef NO_BE_BACKSLASH re.Flags |= REG_BKTESCAPE | REG_BADRANGE; #endif /* !NO_BE_BACKSLASH */ if (re.Expbuf == NULL) re.Expbuf = calloc(1, sizeof (regex_t)); if ((n = regcomp(re.Expbuf, re.Patbuf, re.Flags)) != 0) { switch (n) { case REG_EBRACK: free(re.Expbuf); re.Expbuf = 0; cerror(catgets(catd, 1, 154, "Missing ]")); /*NOTREACHED*/ break; default: regerror(n, re.Expbuf, &re.Patbuf[1], sizeof re.Patbuf - 1); free(re.Expbuf); re.Expbuf = 0; cerror(&re.Patbuf[1]); } } if ((re.Nbra = ((regex_t *)re.Expbuf)->re_nsub) > NBRA) re.Nbra = NBRA; #else /* !UXRE */ if ((re.Expbuf = malloc(re.Length)) == NULL) cerror("Re too complex|Regular expression too complicated"); if (re.Flags & REG_ICASE) { p = malloc(strlen(re.Patbuf) + 1); loconv(p, re.Patbuf); } else p = re.Patbuf; r = _compile(p, re.Expbuf, &((char *)re.Expbuf)[re.Length], '\0'); if (p != re.Patbuf) free(p); if (r == 0) { char *cp; free(re.Expbuf); re.Expbuf = 0; switch (regerrno) { case 11: cp = "Range endpoint too large|Range endpoint " "too large in regular expression"; break; case 16: cp = "Bad number|Bad number in regular expression"; break; case 25: cp = "\"\\digit\" out of range"; break; case 36: cp = "Badly formed re|Missing closing delimiter " "for regular expression"; break; case 42: cp = "\\( \\) Imbalance"; break; case 43: cp = "Awash in \\('s!|Too many \\('d subexressions " "in a regular expression"; break; case 44: cp = "More than 2 numbers given in \\{~\\}"; break; case 45: cp = "} expected after \\"; break; case 46: cp = "First number exceeds second in \\{~\\}"; break; case 49: cp = "Missing ]"; break; case 67: cp = "Illegal byte sequence|Regular expression " "has illegal byte sequence"; break; default: cp = "Unknown regexp error code!!"; } cerror(cp); } re.Circfl = circf; re.Nbra = nbra; #endif /* !UXRE */ re.Re_ident++; } int compile(int eof, int oknl) { int c, d, i, n = 0; char mb[MB_LEN_MAX+1]; char *p = re.Patbuf, *end = re.Patbuf + sizeof re.Patbuf; int nomagic = value(MAGIC) ? 0 : 1, esc, rcnt = 0; char *rhsp; #ifdef BIT8 char *rhsq; #endif if (isalpha(eof) || isdigit(eof)) error(catgets(catd, 1, 133, "Regular expressions cannot be delimited by letters or digits")); c = GETWC(mb); if (eof == '\\') { switch (c) { case '/': case '?': if (scanre.Patbuf[0] == 0) error(catgets(catd, 1, 134, "No previous scan re|No previous scanning regular expression")); resre(&scanre); return c; case '&': if (subre.Patbuf[0] == 0) error(catgets(catd, 1, 135, "No previous substitute re|No previous substitute regular expression")); resre(&subre); return c; default: error(catgets(catd, 1, 136, "Badly formed re|Regular expression \\ must be followed by / or ?")); } } if (c == eof || c == '\n' || c == EOF) { if (c == '\n' && oknl == 0) error(catgets(catd, 1, 138, "Missing closing delimiter@for regular expression")); if (c != eof) ungetchar(c); if (re.Expbuf == 0) error(catgets(catd, 1, 137, "No previous re|No previous regular expression")); return eof; } re.Nbra = re.Circfl = 0; if (c == '^') re.Circfl++; esc = 0; goto havec; /* * Fetch the search pattern. This is quite a mess since we have * to handle nomagic and ~. */ for (;;) { esc = 0; c = GETWC(mb); havec: if (c == eof || c == EOF) { if (c == EOF) ungetchar(c); break; } else if (c == '\n') { if (!oknl) cerror(catgets(catd, 1, 157, "Badly formed re|Missing closing delimiter for regular expression")); ungetchar(c); break; } else if (nomagic) { switch (c) { case '.': case '*': case '[': case '~': *p++ = '\\'; esc = 1; break; case '\\': c = GETWC(mb); if (c != '.' && c != '*' && c != '[' && c != '~') { *p++ = '\\'; esc = 1; } } } else if (c == '\\') { c = GETWC(mb); if (c != '~') *p++ = '\\'; esc = 1; } if (c == EOF) { ungetchar(c); break; } if (!esc && c == '~') { rhsp = rhsbuf; #ifdef BIT8 rhsq = rhsquo; #endif while (*rhsp) { #ifndef BIT8 if (*rhsp & QUOTE) { nextc(c, rhsp, n); c &= TRIM; #else /* BIT8 */ if (*rhsq) { nextc(c, rhsp, n); #endif /* BIT8 */ if (c == '&') error(catgets(catd, 1, 149, "Replacement pattern contains &@- cannot use in re")); if (c >= '1' && c <= '9') error(catgets(catd, 1, 150, "Replacement pattern contains \\d@- cannot use in re")); } if (p >= end - 3) goto complex; if (*rhsp == '\\' || *rhsp == '[' || *rhsp == '.' || *rhsp == '^' || *rhsp == '*' || *rhsp == '$') *p++ = '\\'; #ifdef BIT8 nextc(c, rhsp, n); for (i = 0; i < n; i++) { *p++ = *rhsp++; rhsq++; } #else *p++ = *rhsp++ & TRIM; #endif } } else if (!esc && c == '[') { rcnt++; /* * Search for the end of the bracket expression * since '~' may not be recognized inside. */ *p++ = (char)c; if (p >= end) goto complex; d = EOF; do { c = GETWC(mb); if (c == '\n' || c == EOF) cerror("Missing ]"); for (i = 0; mb[i]; i++) { *p++ = mb[i]; if (p >= end) goto complex; } #ifdef UXRE if (d == '[' && (c == ':' || c == '.' || c == '=')) { d = c; do { c = GETWC(mb); if (c == '\n' || c == EOF) cerror("Missing ]"); for (i = 0; mb[i]; i++) { *p++ = mb[i]; if (p >= end) goto complex; } } while (c != d || peekchar() != ']'); c = GETWC(mb); for (i = 0; mb[i]; i++) { *p++ = mb[i]; if (p >= end) goto complex; } c = EOF; /* -> reset d and continue */ } #endif /* UXRE */ d = c; } while (c != ']'); } else if (esc && c == '{') { /* * Search for the end of the interval expression * since '~' may not be recognized inside. */ for (i = 0; mb[i]; i++) { *p++ = mb[i]; if (p >= end) goto complex; } do { c = GETWC(mb); if (c == '\n' || c == EOF) cerror(catgets(catd, 1, 143, "Bad number|Bad number in regular expression")); for (i = 0; mb[i]; i++) { *p++ = mb[i]; if (p >= end) goto complex; } } while (c != '\\'); c = GETWC(mb); if (c != '}') cerror(catgets(catd, 1, 146, "} expected after \\")); *p++ = (char)c; } else { for (i = 0; mb[i]; i++) { *p++ = mb[i]; if (p >= end) goto complex; } } if (p >= end) complex: cerror(catgets(catd, 1, 139, "Re too complex|Regular expression too complicated")); } if (p == re.Patbuf) *p++ = '.'; /* approximate historical behavior */ *p = '\0'; re.Length = rcnt*32 + 2*(p-re.Patbuf) + 5; compile1(); return eof; } #ifdef UXRE int execute(int gf, line *addr) { char *p; int c; int eflags = 0, nsub; regmatch_t bralist[NBRA + 1]; if (gf) { if (re.Circfl) return 0; eflags |= REG_NOTBOL; p = loc2; } else { if (addr == zero) return 0; if ((value(IGNORECASE) ? 1:0) ^ (re.Flags & REG_ICASE ? 1:0)) compile1(); p = linebuf; getline(*addr); } /* * Need subexpression matches only for substitute command, * so don't fetch them otherwise (enables use of DFA). */ nsub = (re.Re_ident == subre.Re_ident ? NBRA : 0); switch (regexec(re.Expbuf, p, nsub + 1, bralist, eflags)) { case 0: break; case REG_NOMATCH: return 0; default: cerror(catgets(catd, 1, 139, "Re too complex|Regular expression too complicated")); } loc1 = p + bralist[0].rm_so; loc2 = p + bralist[0].rm_eo; for (c = 0; c < nsub; c++) { if (bralist[c + 1].rm_so != -1) { braslist[c] = p + bralist[c + 1].rm_so; braelist[c] = p + bralist[c + 1].rm_eo; } else braslist[c] = braelist[c] = NULL; } return 1; } #else /* !UXRE */ int execute(int gf, line *addr) { char *p; if (gf) { if (re.Circfl) return 0; p = locs = loc2; } else { if (addr == zero) return 0; p = linebuf; getline(*addr); if ((value(IGNORECASE) ? 1:0) ^ (re.Flags & REG_ICASE ? 1:0)) compile1(); if (value(IGNORECASE)) loconv(linebuf, linebuf); locs = 0; } circf = re.Circfl; return step(p, re.Expbuf); } #endif /* !UXRE */