#include "zsh.mdh"
union upat {
long l;
unsigned char *p;
};
typedef union upat *Upat;
#include "pattern.pro"
#define NSUBEXP 9
#define P_END 0x00
#define P_EXCSYNC 0x01
#define P_EXCEND 0x02
#define P_BACK 0x03
#define P_EXACTLY 0x04
#define P_NOTHING 0x05
#define P_ONEHASH 0x06
#define P_TWOHASH 0x07
#define P_GFLAGS 0x08
#define P_ISSTART 0x09
#define P_ISEND 0x0a
#define P_COUNTSTART 0x0b
#define P_COUNT 0x0c
#define P_BRANCH 0x20
#define P_WBRANCH 0x21
#define P_EXCLUDE 0x30
#define P_EXCLUDP 0x31
#define P_ANY 0x40
#define P_ANYOF 0x41
#define P_ANYBUT 0x42
#define P_STAR 0x43
#define P_NUMRNG 0x44
#define P_NUMFROM 0x45
#define P_NUMTO 0x46
#define P_NUMANY 0x47
#define P_OPEN 0x80
#define P_CLOSE 0x90
#define P_OP(p) ((p)->l & 0xff)
#define P_NEXT(p) ((p)->l >> 8)
#define P_OPERAND(p) ((p) + 1)
#define P_ISBRANCH(p) ((p)->l & 0x20)
#define P_ISEXCLUDE(p) (((p)->l & 0x30) == 0x30)
#define P_NOTDOT(p) ((p)->l & 0x40)
#define P_LS_LEN(p) ((p)[1].l)
#define P_LS_STR(p) ((char *)((p) + 2))
#define P_CT_CURRENT (1)
#define P_CT_MIN (2)
#define P_CT_MAX (3)
#define P_CT_PTR (4)
#define P_CT_OPERAND (5)
#define P_SIMPLE 0x01
#define P_HSTART 0x02
#define P_PURESTR 0x04
#if defined(ZSH_64_BIT_TYPE) || defined(LONG_IS_64_BIT)
typedef zlong zrange_t;
#define ZRANGE_T_IS_SIGNED (1)
#else
typedef unsigned long zrange_t;
#endif
static char endseg[] = {
'/',
'\0', Bar, Outpar,
Tilde
};
#define PATENDSEGLEN_NORM 4
#define PATENDSEGLEN_EXT 5
static char endstr[] = {
'/',
'\0', Bar, Outpar, Quest, Star, Inbrack, Inpar, Inang, Bnullkeep,
Tilde, Hat, Pound
};
#define PATENDSTRLEN_NORM 10
#define PATENDSTRLEN_EXT 13
#define P_DEF_ALLOC 256
static char *patstart, *patparse;
static int patnpar;
static char *patcode;
static long patsize;
static char *patout;
static long patalloc;
static char *patendseg;
static int patendseglen;
static char *patendstr;
static int patendstrlen;
static int patflags;
static int patglobflags;
#ifdef MULTIBYTE_SUPPORT
typedef wint_t patint_t;
#define PEOF WEOF
#define METACHARINC(x) ((void)metacharinc(&x))
static mbstate_t shiftstate;
static wchar_t
metacharinc(char **x)
{
char *inptr = *x;
char inchar;
size_t ret = MB_INVALID;
wchar_t wc;
if (!(patglobflags & GF_MULTIBYTE) || !(STOUC(*inptr) & 0x80))
{
if (itok(*inptr))
inchar = ztokens[*inptr++ - Pound];
else if (*inptr == Meta) {
inptr++;
inchar = *inptr++ ^ 32;
} else {
inchar = *inptr++;
}
*x = inptr;
return (wchar_t)STOUC(inchar);
}
while (*inptr) {
if (itok(*inptr))
inchar = ztokens[*inptr++ - Pound];
else if (*inptr == Meta) {
inptr++;
inchar = *inptr++ ^ 32;
} else {
inchar = *inptr++;
}
ret = mbrtowc(&wc, &inchar, 1, &shiftstate);
if (ret == MB_INVALID)
break;
if (ret == MB_INCOMPLETE)
continue;
*x = inptr;
return wc;
}
memset(&shiftstate, 0, sizeof(shiftstate));
return (wchar_t) STOUC(*(*x)++);
}
#else
typedef int patint_t;
#define PEOF EOF
#define METACHARINC(x) ((void)((x) += (*(x) == Meta) ? 2 : 1))
#endif
#define UNMETA(x) (*(x) == Meta ? (x)[1] ^ 32 : *(x))
enum {
PA_NOALIGN = 1,
PA_UNMETA = 2
};
static void
patadd(char *add, int ch, long n, int paflags)
{
long newpatsize = patsize + n;
if (!(paflags & PA_NOALIGN))
newpatsize = (newpatsize + sizeof(union upat) - 1) &
~(sizeof(union upat) - 1);
if (patalloc < newpatsize) {
long newpatalloc =
2*(newpatsize > patalloc ? newpatsize : patalloc);
patout = (char *)zrealloc((char *)patout, newpatalloc);
patcode = patout + patsize;
patalloc = newpatalloc;
}
patsize = newpatsize;
if (add) {
if (paflags & PA_UNMETA) {
while (n--) {
if (itok(*add))
*patcode++ = ztokens[*add++ - Pound];
else if (*add == Meta) {
add++;
*patcode++ = *add++ ^ 32;
} else {
*patcode++ = *add++;
}
}
} else {
while (n--)
*patcode++ = *add++;
}
} else
*patcode++ = ch;
patcode = patout + patsize;
}
static long rn_offs;
#define PATNEXT(p) ((rn_offs = P_NEXT(p)) ? \
(P_OP(p) == P_BACK) ? \
((p)-rn_offs) : ((p)+rn_offs) : NULL)
void
patcompstart(void)
{
if (isset(CASEGLOB))
patglobflags = 0;
else
patglobflags = GF_IGNCASE;
if (isset(MULTIBYTE))
patglobflags |= GF_MULTIBYTE;
}
mod_export Patprog
patcompile(char *exp, int inflags, char **endexp)
{
int flags = 0;
long len = 0;
long startoff;
Upat pscan;
char *lng, *strp = NULL;
Patprog p;
startoff = sizeof(struct patprog);
startoff = (startoff + sizeof(union upat) - 1) & ~(sizeof(union upat) - 1);
if (patalloc != P_DEF_ALLOC)
patout = (char *)zrealloc(patout, patalloc = P_DEF_ALLOC);
patcode = patout + startoff;
patsize = patcode - patout;
patstart = patparse = exp;
patnpar = 1;
patflags = inflags & ~(PAT_PURES|PAT_HAS_EXCLUDP);
patendseg = endseg;
patendseglen = isset(EXTENDEDGLOB) ? PATENDSEGLEN_EXT : PATENDSEGLEN_NORM;
patendstr = endstr;
patendstrlen = isset(EXTENDEDGLOB) ? PATENDSTRLEN_EXT : PATENDSTRLEN_NORM;
if (!(patflags & PAT_FILE)) {
patendseg++;
patendstr++;
patendseglen--;
patendstrlen--;
remnulargs(patparse);
if (isset(MULTIBYTE))
patglobflags = GF_MULTIBYTE;
else
patglobflags = 0;
}
if (patflags & PAT_LCMATCHUC)
patglobflags |= GF_LCMATCHUC;
((Patprog)patout)->globflags = patglobflags;
if (!(patflags & PAT_ANY)) {
if (!(patglobflags & ~GF_MULTIBYTE)
#ifdef __CYGWIN__
|| (!(patglobflags & ~GF_IGNCASE) && (patflags & PAT_FILE))
#endif
)
{
if (*exp == Nularg)
exp++;
for (strp = exp; *strp &&
(!(patflags & PAT_FILE) || *strp != '/') && !itok(*strp);
strp++)
;
}
if (!strp || (*strp && *strp != '/')) {
strp = NULL;
if (patcompswitch(0, &flags) == 0)
return NULL;
} else {
patparse = strp;
len = strp - exp;
patadd(exp, 0, len + 1, 0);
patout[startoff + len] = '\0';
patflags |= PAT_PURES;
}
}
p = (Patprog)patout;
p->startoff = startoff;
p->patstartch = '\0';
p->globend = patglobflags;
p->flags = patflags;
p->mustoff = 0;
p->size = patsize;
p->patmlen = len;
p->patnpar = patnpar-1;
if (!strp) {
pscan = (Upat)(patout + startoff);
if (!(patflags & PAT_ANY) && P_OP(PATNEXT(pscan)) == P_END) {
pscan = P_OPERAND(pscan);
if (flags & P_PURESTR) {
char *dst = patout + startoff;
Upat next;
p->flags |= PAT_PURES;
for (; pscan; pscan = next) {
next = PATNEXT(pscan);
if (P_OP(pscan) == P_EXACTLY) {
char *opnd = P_LS_STR(pscan), *mtest;
long oplen = P_LS_LEN(pscan), ilen;
int nmeta = 0;
for (mtest = opnd, ilen = oplen; ilen;
mtest++, ilen--)
if (imeta(*mtest))
nmeta++;
if (nmeta) {
char *oldpatout = patout;
patadd(NULL, 0, nmeta, 0);
p = (Patprog)patout;
opnd = patout + (opnd - oldpatout);
dst = patout + startoff;
}
while (oplen--) {
if (imeta(*opnd)) {
*dst++ = Meta;
*dst++ = *opnd++ ^ 32;
} else {
*dst++ = *opnd++;
}
}
}
}
p->size = dst - patout;
p->patmlen = p->size - startoff;
} else {
if (P_OP(pscan) == P_EXACTLY && !p->globflags &&
P_LS_LEN(pscan))
p->patstartch = *P_LS_STR(pscan);
if ((flags & P_HSTART) && !p->globflags) {
lng = NULL;
len = 0;
for (; pscan; pscan = PATNEXT(pscan))
if (P_OP(pscan) == P_EXACTLY &&
P_LS_LEN(pscan) >= len) {
lng = P_LS_STR(pscan);
len = P_LS_LEN(pscan);
}
if (lng) {
p->mustoff = lng - patout;
p->patmlen = len;
}
}
}
}
}
if (patflags & PAT_ZDUP) {
Patprog newp = (Patprog)zalloc(patsize);
memcpy((char *)newp, (char *)p, patsize);
p = newp;
} else if (!(patflags & PAT_STATIC)) {
Patprog newp = (Patprog)zhalloc(patsize);
memcpy((char *)newp, (char *)p, patsize);
p = newp;
}
if (endexp)
*endexp = patparse;
return p;
}
static long
patcompswitch(int paren, int *flagp)
{
long starter, br, ender, excsync = 0;
int parno = 0;
int flags, gfchanged = 0, savglobflags = patglobflags;
Upat ptr;
*flagp = 0;
if (paren && (patglobflags & GF_BACKREF) && patnpar <= NSUBEXP) {
parno = patnpar++;
starter = patnode(P_OPEN + parno);
} else
starter = 0;
br = patnode(P_BRANCH);
if (!patcompbranch(&flags))
return 0;
if (patglobflags != savglobflags)
gfchanged++;
if (starter)
pattail(starter, br);
else
starter = br;
*flagp |= flags & (P_HSTART|P_PURESTR);
while (*patparse == Bar ||
(isset(EXTENDEDGLOB) && *patparse == Tilde &&
(patparse[1] == '/' ||
!memchr(patendseg, patparse[1], patendseglen)))) {
int tilde = *patparse++ == Tilde;
long gfnode = 0, newbr;
*flagp &= ~P_PURESTR;
if (tilde) {
union upat up;
if (!excsync) {
excsync = patnode(P_EXCSYNC);
patoptail(br, excsync);
}
patglobflags &= ~0xff;
if (!(patflags & PAT_FILET) || paren) {
br = patnode(P_EXCLUDE);
} else {
br = patnode(P_EXCLUDP);
patflags |= PAT_HAS_EXCLUDP;
}
up.p = NULL;
patadd((char *)&up, 0, sizeof(up), 0);
if (!paren && *patendseg == '/') {
tilde++;
patendseg++;
patendseglen--;
patendstr++;
patendstrlen--;
}
} else {
excsync = 0;
br = patnode(P_BRANCH);
if (!paren) {
patglobflags = 0;
if (((Patprog)patout)->globflags) {
union upat up;
gfnode = patnode(P_GFLAGS);
up.l = patglobflags;
patadd((char *)&up, 0, sizeof(union upat), 0);
}
} else {
patglobflags = savglobflags;
}
}
newbr = patcompbranch(&flags);
if (tilde == 2) {
patendseg--;
patendseglen++;
patendstr--;
patendstrlen++;
}
if (!newbr)
return 0;
if (gfnode)
pattail(gfnode, newbr);
if (!tilde && patglobflags != savglobflags)
gfchanged++;
pattail(starter, br);
if (excsync)
patoptail(br, patnode(P_EXCEND));
*flagp |= flags & P_HSTART;
}
ender = patnode(paren ? parno ? P_CLOSE+parno : P_NOTHING : P_END);
pattail(starter, ender);
for (ptr = (Upat)patout + starter; ptr; ptr = PATNEXT(ptr))
if (!P_ISEXCLUDE(ptr))
patoptail(ptr-(Upat)patout, ender);
if ((paren && *patparse++ != Outpar) ||
(!paren && *patparse &&
!((patflags & PAT_FILE) && *patparse == '/')))
return 0;
if (paren && gfchanged) {
pattail(ender, patnode(P_GFLAGS));
patglobflags = savglobflags;
patadd((char *)&savglobflags, 0, sizeof(long), 0);
}
return starter;
}
static long
patcompbranch(int *flagp)
{
long chain, latest = 0, starter;
int flags = 0;
*flagp = P_PURESTR;
starter = chain = 0;
while (!memchr(patendseg, *patparse, patendseglen) ||
(*patparse == Tilde && patparse[1] != '/' &&
memchr(patendseg, patparse[1], patendseglen))) {
if (isset(EXTENDEDGLOB) &&
((!isset(SHGLOB) &&
(*patparse == Inpar && patparse[1] == Pound)) ||
(isset(KSHGLOB) && *patparse == '@' && patparse[1] == Inpar &&
patparse[2] == Pound))) {
char *pp1 = patparse;
int oldglobflags = patglobflags, ignore;
long assert;
patparse += (*patparse == '@') ? 3 : 2;
if (!patgetglobflags(&patparse, &assert, &ignore))
return 0;
if (!ignore) {
if (assert) {
latest = patnode(assert);
flags = 0;
} else {
if (pp1 == patstart) {
((Patprog)patout)->globflags = patglobflags;
continue;
} else if (!*patparse) {
break;
}
if (oldglobflags != patglobflags) {
union upat up;
latest = patnode(P_GFLAGS);
up.l = patglobflags;
patadd((char *)&up, 0, sizeof(union upat), 0);
} else {
continue;
}
}
} else if (!*patparse)
break;
else
continue;
} else if (isset(EXTENDEDGLOB) && *patparse == Hat) {
patparse++;
latest = patcompnot(0, &flags);
} else
latest = patcomppiece(&flags);
if (!latest)
return 0;
if (!starter)
starter = latest;
if (!(flags & P_PURESTR))
*flagp &= ~P_PURESTR;
if (!chain)
*flagp |= flags & P_HSTART;
else
pattail(chain, latest);
chain = latest;
}
if (!chain)
starter = patnode(P_NOTHING);
return starter;
}
int
patgetglobflags(char **strp, long *assertp, int *ignore)
{
char *nptr, *ptr = *strp;
zlong ret;
*assertp = 0;
*ignore = 1;
for (; *ptr && *ptr != Outpar; ptr++) {
if (*ptr == 'q') {
while (*ptr && *ptr != Outpar)
ptr++;
break;
} else {
*ignore = 0;
switch (*ptr) {
case 'a':
ret = zstrtol(++ptr, &nptr, 10);
if (ret < 0 || ret > 254 || ptr == nptr)
return 0;
patglobflags = (patglobflags & ~0xff) | (ret & 0xff);
ptr = nptr-1;
break;
case 'l':
patglobflags = (patglobflags & ~GF_IGNCASE) | GF_LCMATCHUC;
break;
case 'i':
patglobflags = (patglobflags & ~GF_LCMATCHUC) | GF_IGNCASE;
break;
case 'I':
patglobflags &= ~(GF_LCMATCHUC|GF_IGNCASE);
break;
case 'b':
patglobflags |= GF_BACKREF;
break;
case 'B':
patglobflags &= ~GF_BACKREF;
break;
case 'm':
patglobflags |= GF_MATCHREF;
break;
case 'M':
patglobflags &= ~GF_MATCHREF;
break;
case 's':
*assertp = P_ISSTART;
break;
case 'e':
*assertp = P_ISEND;
break;
case 'u':
patglobflags |= GF_MULTIBYTE;
break;
case 'U':
patglobflags &= ~GF_MULTIBYTE;
break;
default:
return 0;
}
}
}
if (*ptr != Outpar)
return 0;
if (*assertp && (*strp)[1] != Outpar)
return 0;
*strp = ptr + 1;
return 1;
}
static const char *colon_stuffs[] = {
"alpha", "alnum", "ascii", "blank", "cntrl", "digit", "graph",
"lower", "print", "punct", "space", "upper", "xdigit", "IDENT",
"IFS", "IFSSPACE", "WORD", NULL
};
mod_export int
range_type(char *start, int len)
{
const char **csp;
for (csp = colon_stuffs; *csp; csp++) {
if (!strncmp(start, *csp, len))
return (csp - colon_stuffs) + PP_FIRST;
}
return PP_UNKWN;
}
mod_export int
pattern_range_to_string(char *rangestr, char *outstr)
{
int len = 0;
while (*rangestr) {
if (imeta(STOUC(*rangestr))) {
int swtype = STOUC(*rangestr) - STOUC(Meta);
if (swtype == 0) {
if (outstr)
{
*outstr++ = Meta;
*outstr++ = rangestr[1] ^ 32;
}
len += 2;
rangestr += 2;
} else if (swtype == PP_RANGE) {
int i;
for (i = 0; i < 2; i++) {
if (*rangestr == Meta) {
if (outstr) {
*outstr++ = Meta;
*outstr++ = rangestr[1];
}
len += 2;
rangestr += 2;
} else {
if (outstr)
*outstr++ = *rangestr;
len++;
rangestr++;
}
if (i == 0) {
if (outstr)
*outstr++ = '-';
len++;
}
}
} else if (swtype >= PP_FIRST && swtype <= PP_LAST) {
const char *found = colon_stuffs[swtype - PP_FIRST];
int newlen = strlen(found);
if (outstr) {
strcpy(outstr, "[:");
outstr += 2;
memcpy(outstr, found, newlen);
outstr += newlen;
strcpy(outstr, ":]");
outstr += 2;
}
len += newlen + 4;
rangestr++;
} else {
DPUTS(1, "BUG: unknown PP_ code in pattern range");
rangestr++;
}
} else {
if (outstr)
*outstr++ = *rangestr;
len++;
rangestr++;
}
}
if (outstr)
*outstr = '\0';
return len;
}
static long
patcomppiece(int *flagp)
{
long starter = 0, next, op, opnd;
int flags, flags2, kshchar, len, ch, patch, nmeta;
int pound, count;
union upat up;
char *nptr, *str0, *ptr, *patprev;
zrange_t from, to;
char *charstart;
flags = 0;
str0 = patprev = patparse;
for (;;) {
kshchar = '\0';
if (isset(KSHGLOB) && *patparse && patparse[1] == Inpar) {
if (strchr("?*+!@", *patparse))
kshchar = STOUC(*patparse);
else if (*patparse == Star || *patparse == Quest)
kshchar = STOUC(ztokens[*patparse - Pound]);
}
if (kshchar || (memchr(patendstr, *patparse, patendstrlen) &&
(*patparse != Tilde ||
patparse[1] == '/' ||
!memchr(patendseg, patparse[1], patendseglen))))
break;
patprev = patparse;
METACHARINC(patparse);
}
if (patparse > str0) {
long slen = patparse - str0;
int morelen;
kshchar = '\0';
flags |= P_PURESTR;
DPUTS(patparse == str0, "BUG: matched nothing in patcomppiece.");
morelen = (patprev > str0);
if (isset(EXTENDEDGLOB) &&
(*patparse == Pound ||
(*patparse == Inpar && patparse[1] == Pound &&
patparse[2] == 'c')) && morelen)
patparse = patprev;
if (!morelen)
flags |= P_SIMPLE;
starter = patnode(P_EXACTLY);
nmeta = 0;
if (*str0 == Nularg)
str0++;
for (ptr = str0; ptr < patparse; ptr++) {
if (*ptr == Meta) {
nmeta++;
ptr++;
}
}
slen = (patparse - str0) - nmeta;
patadd((char *)&slen, 0, sizeof(long), 0);
patadd(str0, 0, slen, PA_UNMETA);
nptr = P_LS_STR((Upat)patout + starter);
if (patglobflags &
#ifdef __CYGWIN__
((patflags & PAT_FILE) ?
(0xFF|GF_LCMATCHUC) :
(0xFF|GF_LCMATCHUC|GF_IGNCASE))
#else
(0xFF|GF_LCMATCHUC|GF_IGNCASE)
#endif
) {
if (!(patflags & PAT_FILE))
flags &= ~P_PURESTR;
else if (!(nptr[0] == '.' &&
(slen == 1 || (nptr[1] == '.' && slen == 2))))
flags &= ~P_PURESTR;
}
} else {
if (kshchar)
patparse++;
patch = *patparse;
METACHARINC(patparse);
switch(patch) {
case Quest:
flags |= P_SIMPLE;
starter = patnode(P_ANY);
break;
case Star:
kshchar = -1;
starter = patnode(P_STAR);
break;
case Inbrack:
flags |= P_SIMPLE;
if (*patparse == Hat || *patparse == '^' || *patparse == '!') {
patparse++;
starter = patnode(P_ANYBUT);
} else
starter = patnode(P_ANYOF);
if (*patparse == Outbrack) {
patparse++;
patadd(NULL, ']', 1, PA_NOALIGN);
}
while (*patparse && *patparse != Outbrack) {
if (*patparse == Inbrack && patparse[1] == ':' &&
(nptr = strchr(patparse+2, ':')) &&
nptr[1] == Outbrack) {
patparse += 2;
len = nptr - patparse;
ch = range_type(patparse, len);
patparse = nptr + 2;
if (ch != PP_UNKWN)
patadd(NULL, STOUC(Meta) + ch, 1, PA_NOALIGN);
continue;
}
charstart = patparse;
METACHARINC(patparse);
if (*patparse == '-' && patparse[1] &&
patparse[1] != Outbrack) {
patadd(NULL, STOUC(Meta)+PP_RANGE, 1, PA_NOALIGN);
if (itok(*charstart)) {
patadd(0, STOUC(ztokens[*charstart - Pound]), 1,
PA_NOALIGN);
} else {
patadd(charstart, 0, patparse-charstart, PA_NOALIGN);
}
charstart = ++patparse;
METACHARINC(patparse);
}
if (itok(*charstart)) {
patadd(0, STOUC(ztokens[*charstart - Pound]), 1,
PA_NOALIGN);
} else {
patadd(charstart, 0, patparse-charstart, PA_NOALIGN);
}
}
if (*patparse != Outbrack)
return 0;
patparse++;
patadd(NULL, 0, 1, 0);
break;
case Inpar:
if (isset(SHGLOB) && !kshchar)
return 0;
if (kshchar == '!') {
if (!(starter = patcompnot(1, &flags2)))
return 0;
} else if (!(starter = patcompswitch(1, &flags2)))
return 0;
flags |= flags2 & P_HSTART;
break;
case Inang:
len = 0;
if (idigit(*patparse)) {
from = (zrange_t) zstrtol((char *)patparse,
(char **)&nptr, 10);
patparse = nptr;
len |= 1;
}
DPUTS(*patparse != '-', "BUG: - missing from numeric glob");
patparse++;
if (idigit(*patparse)) {
to = (zrange_t) zstrtol((char *)patparse,
(char **)&nptr, 10);
patparse = nptr;
len |= 2;
}
if (*patparse != Outang)
return 0;
patparse++;
switch(len) {
case 3:
starter = patnode(P_NUMRNG);
patadd((char *)&from, 0, sizeof(from), 0);
patadd((char *)&to, 0, sizeof(to), 0);
break;
case 2:
starter = patnode(P_NUMTO);
patadd((char *)&to, 0, sizeof(to), 0);
break;
case 1:
starter = patnode(P_NUMFROM);
patadd((char *)&from, 0, sizeof(from), 0);
break;
case 0:
starter = patnode(P_NUMANY);
break;
}
break;
case Pound:
DPUTS(!isset(EXTENDEDGLOB), "BUG: # not treated as string");
return 0;
break;
case Bnullkeep:
next = patcomppiece(flagp);
*flagp &= ~P_PURESTR;
return next;
break;
#ifdef DEBUG
default:
dputs("BUG: character not handled in patcomppiece");
return 0;
break;
#endif
}
}
count = 0;
if (!(pound = (*patparse == Pound && isset(EXTENDEDGLOB))) &&
!(count = (isset(EXTENDEDGLOB) && *patparse == Inpar &&
patparse[1] == Pound && patparse[2] == 'c')) &&
(kshchar <= 0 || kshchar == '@' || kshchar == '!')) {
*flagp = flags;
return starter;
}
if (kshchar && pound)
return 0;
if (kshchar == '*') {
op = P_ONEHASH;
*flagp = P_HSTART;
} else if (kshchar == '+') {
op = P_TWOHASH;
*flagp = P_HSTART;
} else if (kshchar == '?') {
op = 0;
*flagp = 0;
} else if (count) {
op = P_COUNT;
patparse += 3;
*flagp = P_HSTART;
} else if (*++patparse == Pound) {
op = P_TWOHASH;
patparse++;
*flagp = P_HSTART;
} else {
op = P_ONEHASH;
*flagp = P_HSTART;
}
if (op == P_COUNT) {
union upat countargs[P_CT_OPERAND];
char *opp = patparse;
countargs[0].l = P_COUNT;
countargs[P_CT_CURRENT].l = 0L;
countargs[P_CT_MIN].l = (long)zstrtol(patparse, &patparse, 10);
if (patparse == opp) {
countargs[P_CT_MIN].l = 0L;
}
if (*patparse != ',' && *patparse != Comma) {
if (*patparse != Outpar)
return 0;
countargs[P_CT_MAX].l = countargs[P_CT_MIN].l;
} else {
opp = ++patparse;
countargs[P_CT_MAX].l = (long)zstrtol(patparse, &patparse, 10);
if (*patparse != Outpar)
return 0;
if (patparse == opp) {
countargs[P_CT_MAX].l = -1L;
}
}
patparse++;
countargs[P_CT_PTR].p = NULL;
patinsert(P_COUNTSTART, starter, (char *)countargs, sizeof(countargs));
opnd = P_OPERAND(starter) + P_CT_OPERAND;
pattail(opnd, patnode(P_BACK));
pattail(opnd, P_OPERAND(starter));
next = patnode(P_NOTHING);
pattail(starter, next);
pattail(P_OPERAND(starter), next);
} else if ((flags & P_SIMPLE) && (op == P_ONEHASH || op == P_TWOHASH) &&
P_OP((Upat)patout+starter) == P_ANY) {
Upat uptr = (Upat)patout + starter;
if (op == P_TWOHASH) {
uptr->l = (uptr->l & ~0xff) | P_ANY;
pattail(starter, patnode(P_STAR));
} else {
uptr->l = (uptr->l & ~0xff) | P_STAR;
}
} else if ((flags & P_SIMPLE) && op && !(patglobflags & 0xff)) {
patinsert(op, starter, NULL, 0);
} else if (op == P_ONEHASH) {
up.p = NULL;
patinsert(P_WBRANCH, starter, (char *)&up, sizeof(up));
patoptail(starter, patnode(P_BACK));
patoptail(starter, starter);
pattail(starter, patnode(P_BRANCH));
pattail(starter, patnode(P_NOTHING));
} else if (op == P_TWOHASH) {
next = patnode(P_WBRANCH);
up.p = NULL;
patadd((char *)&up, 0, sizeof(up), 0);
pattail(starter, next);
pattail(patnode(P_BACK), starter);
pattail(next, patnode(P_BRANCH));
pattail(starter, patnode(P_NOTHING));
} else if (kshchar == '?') {
patinsert(P_BRANCH, starter, NULL, 0);
pattail(starter, patnode(P_BRANCH));
next = patnode(P_NOTHING);
pattail(starter, next);
patoptail(starter, next);
}
if (*patparse == Pound)
return 0;
return starter;
}
static long
patcompnot(int paren, int *flagsp)
{
union upat up;
long excsync, br, excl, n, starter;
int dummy;
*flagsp = P_HSTART;
starter = patnode(P_BRANCH);
br = patnode(P_STAR);
excsync = patnode(P_EXCSYNC);
pattail(br, excsync);
pattail(starter, excl = patnode(P_EXCLUDE));
up.p = NULL;
patadd((char *)&up, 0, sizeof(up), 0);
if (!(br = (paren ? patcompswitch(1, &dummy) : patcompbranch(&dummy))))
return 0;
pattail(br, patnode(P_EXCEND));
n = patnode(P_NOTHING);
pattail(excsync, n);
pattail(excl, n);
return starter;
}
static long
patnode(long op)
{
long starter = (Upat)patcode - (Upat)patout;
union upat up;
up.l = op;
patadd((char *)&up, 0, sizeof(union upat), 0);
return starter;
}
static void
patinsert(long op, int opnd, char *xtra, int sz)
{
char *src, *dst, *opdst;
union upat buf, *lptr;
buf.l = 0;
patadd((char *)&buf, 0, sizeof(buf), 0);
if (sz)
patadd(xtra, 0, sz, 0);
src = patcode - sizeof(union upat) - sz;
dst = patcode;
opdst = patout + opnd * sizeof(union upat);
while (src > opdst)
*--dst = *--src;
lptr = (Upat)opdst;
lptr->l = op;
opdst += sizeof(union upat);
while (sz--)
*opdst++ = *xtra++;
}
static void
pattail(long p, long val)
{
Upat scan, temp;
long offset;
scan = (Upat)patout + p;
for (;;) {
if (!(temp = PATNEXT(scan)))
break;
scan = temp;
}
offset = (P_OP(scan) == P_BACK)
? (scan - (Upat)patout) - val : val - (scan - (Upat)patout);
scan->l |= offset << 8;
}
static void patoptail(long p, long val)
{
Upat ptr = (Upat)patout + p;
int op = P_OP(ptr);
if (!p || !P_ISBRANCH(ptr))
return;
if (op == P_BRANCH)
pattail(P_OPERAND(p), val);
else
pattail(P_OPERAND(p) + 1, val);
}
static char *patinstart;
static char *patinend;
static char *patinput;
static char *patinpath;
static int patinlen;
static char *patbeginp[NSUBEXP];
static char *patendp[NSUBEXP];
static int parsfound;
static int globdots;
#ifdef MULTIBYTE_SUPPORT
#define CHARREF(x, y) charref((x), (y))
static wchar_t
charref(char *x, char *y)
{
wchar_t wc;
size_t ret;
if (!(patglobflags & GF_MULTIBYTE) || !(STOUC(*x) & 0x80))
return (wchar_t) STOUC(*x);
ret = mbrtowc(&wc, x, y-x, &shiftstate);
if (ret == MB_INVALID || ret == MB_INCOMPLETE) {
memset(&shiftstate, 0, sizeof(shiftstate));
return (wchar_t) STOUC(*x);
}
return wc;
}
#define CHARNEXT(x, y) charnext((x), (y))
static char *
charnext(char *x, char *y)
{
wchar_t wc;
size_t ret;
if (!(patglobflags & GF_MULTIBYTE) || !(STOUC(*x) & 0x80))
return x + 1;
ret = mbrtowc(&wc, x, y-x, &shiftstate);
if (ret == MB_INVALID || ret == MB_INCOMPLETE) {
memset(&shiftstate, 0, sizeof(shiftstate));
return x + 1;
}
return x + (ret ? ret : 1);
}
#define CHARINC(x, y) ((x) = charnext((x), (y)))
#define CHARREFINC(x, y) charrefinc(&(x), (y))
static wchar_t
charrefinc(char **x, char *y)
{
wchar_t wc;
size_t ret;
if (!(patglobflags & GF_MULTIBYTE) || !(STOUC(**x) & 0x80))
return (wchar_t) STOUC(*(*x)++);
ret = mbrtowc(&wc, *x, y-*x, &shiftstate);
if (ret == MB_INVALID || ret == MB_INCOMPLETE) {
memset(&shiftstate, 0, sizeof(shiftstate));
return (wchar_t) STOUC(*(*x)++);
}
*x += ret ? ret : 1;
return wc;
}
#define CHARSUB(x,y) charsub(x, y)
static ptrdiff_t
charsub(char *x, char *y)
{
ptrdiff_t res = 0;
size_t ret;
wchar_t wc;
if (!isset(MULTIBYTE))
return y - x;
while (x < y) {
ret = mbrtowc(&wc, x, y-x, &shiftstate);
if (ret == MB_INVALID || ret == MB_INCOMPLETE) {
return res + (y - x);
}
if (!ret)
ret = 1;
res++;
x += ret;
}
return res;
}
#else
#define CHARREF(x, y) (STOUC(*(x)))
#define CHARNEXT(x, y) ((x)+1)
#define CHARINC(x, y) ((x)++)
#define CHARREFINC(x, y) (STOUC(*(x)++))
#define CHARSUB(x,y) ((y) - (x))
#endif
int errsfound;
int forceerrs;
void
pattrystart(void)
{
forceerrs = -1;
errsfound = 0;
}
mod_export int
pattry(Patprog prog, char *string)
{
return pattryrefs(prog, string, -1, -1, 0, NULL, NULL, NULL);
}
mod_export int
pattrylen(Patprog prog, char *string, int len, int unmetalen, int offset)
{
return pattryrefs(prog, string, len, unmetalen, offset, NULL, NULL, NULL);
}
mod_export int
pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen,
int patoffset,
int *nump, int *begp, int *endp)
{
int i, maxnpos = 0, ret, needfullpath, unmetalenp;
int origlen;
char **sp, **ep, *tryalloced, *ptr;
char *progstr = (char *)prog + prog->startoff;
if (nump) {
maxnpos = *nump;
*nump = 0;
}
if (*string == Nularg) {
string++;
unmetalen--;
}
if (stringlen < 0)
stringlen = strlen(string);
origlen = stringlen;
patflags = prog->flags;
needfullpath = (patflags & PAT_HAS_EXCLUDP) && pathpos;
if (unmetalen < 0)
unmetalen = ztrsub(string + stringlen, string);
if (needfullpath)
unmetalenp = ztrsub(pathbuf + pathpos, pathbuf);
else
unmetalenp = 0;
DPUTS(needfullpath && (patflags & (PAT_PURES|PAT_ANY)),
"rum sort of file exclusion");
if (!(patflags & (PAT_PURES|PAT_ANY))
&& (needfullpath || unmetalen != stringlen)) {
char *dst;
int icopy, ncopy;
dst = tryalloced = zalloc(unmetalen + unmetalenp);
if (needfullpath) {
ptr = pathbuf;
ncopy = unmetalenp;
} else {
ptr = string;
ncopy = unmetalen;
}
for (icopy = 0; icopy < 2; icopy++) {
for (i = 0; i < ncopy; i++) {
if (*ptr == Meta) {
ptr++;
*dst++ = *ptr++ ^ 32;
} else {
*dst++ = *ptr++;
}
}
if (!needfullpath)
break;
ptr = string;
ncopy = unmetalen;
}
if (needfullpath) {
patinstart = tryalloced + unmetalenp;
patinpath = tryalloced;
} else {
patinstart = tryalloced;
patinpath = NULL;
}
stringlen = unmetalen;
} else {
patinstart = string;
tryalloced = patinpath = NULL;
}
patinend = patinstart + stringlen;
if (prog->flags & (PAT_PURES|PAT_ANY)) {
int ret;
if (prog->flags & PAT_ANY) {
ret = 1;
} else {
int lendiff = stringlen - prog->patmlen;
if (lendiff < 0) {
ret = 0;
} else if (!memcmp(progstr, patinstart, prog->patmlen)) {
ret = !lendiff || (prog->flags & PAT_NOANCH);
} else {
ret = 0;
}
}
if (ret) {
if ((prog->flags & PAT_NOGLD) && *patinstart == '.') {
ret = 0;
} else {
patinlen = (int)prog->patmlen;
patglobflags = prog->globend;
if ((patglobflags & GF_MATCHREF) &&
!(patflags & PAT_FILE)) {
char *str = ztrduppfx(patinstart, patinlen);
char *ptr = patinstart;
int mlen = 0;
MB_METACHARINIT();
while (ptr < patinstart + patinlen) {
mlen++;
ptr += MB_METACHARLEN(ptr);
}
setsparam("MATCH", str);
setiparam("MBEGIN",
(zlong)(patoffset + !isset(KSHARRAYS)));
setiparam("MEND",
(zlong)(mlen + patoffset +
!isset(KSHARRAYS) - 1));
}
}
}
if (tryalloced)
zfree(tryalloced, unmetalen + unmetalenp);
return ret;
} else {
ret = 1;
if (!(prog->flags & PAT_SCAN) && prog->mustoff)
{
char *testptr;
char *teststop;
char *patptr = (char *)prog + prog->mustoff;
int patlen = prog->patmlen;
int found = 0;
if (patlen > stringlen) {
ret = 0;
} else {
teststop = patinend - patlen;
for (testptr = patinstart; testptr <= teststop; testptr++)
{
if (!memcmp(testptr, patptr, patlen)) {
found = 1;
break;
}
}
if (!found)
ret = 0;
}
}
if (!ret) {
if (tryalloced)
zfree(tryalloced, unmetalen + unmetalenp);
return 0;
}
patglobflags = prog->globflags;
if (!(patflags & PAT_FILE)) {
forceerrs = -1;
errsfound = 0;
}
globdots = !(patflags & PAT_NOGLD);
parsfound = 0;
patinput = patinstart;
if (patmatch((Upat)progstr)) {
patglobflags = prog->globend;
patinlen = patinput - patinstart;
if (unmetalen != origlen) {
for (ptr = patinstart; ptr < patinput; ptr++)
if (imeta(*ptr))
patinlen++;
}
if ((patglobflags & GF_MATCHREF) && !(patflags & PAT_FILE)) {
char *str;
int mlen = CHARSUB(patinstart, patinput);
str = metafy(patinstart, patinput - patinstart, META_DUP);
setsparam("MATCH", str);
setiparam("MBEGIN", (zlong)(patoffset + !isset(KSHARRAYS)));
setiparam("MEND",
(zlong)(mlen + patoffset +
!isset(KSHARRAYS) - 1));
}
if (prog->patnpar && nump) {
*nump = prog->patnpar;
sp = patbeginp;
ep = patendp;
for (i = 0; i < prog->patnpar && i < maxnpos; i++) {
if (parsfound & (1 << i)) {
if (begp)
*begp++ = CHARSUB(patinstart, *sp) + patoffset;
if (endp)
*endp++ = CHARSUB(patinstart, *ep) + patoffset
- 1;
} else {
if (begp)
*begp++ = -1;
if (endp)
*endp++ = -1;
}
sp++;
ep++;
}
} else if (prog->patnpar && !(patflags & PAT_FILE)) {
int palen = prog->patnpar+1;
char **matcharr, **mbeginarr, **mendarr;
char numbuf[DIGBUFSIZE];
matcharr = zshcalloc(palen*sizeof(char *));
mbeginarr = zshcalloc(palen*sizeof(char *));
mendarr = zshcalloc(palen*sizeof(char *));
sp = patbeginp;
ep = patendp;
for (i = 0; i < prog->patnpar; i++) {
if (parsfound & (1 << i)) {
matcharr[i] = metafy(*sp, *ep - *sp, META_DUP);
sprintf(numbuf, "%ld",
(long)(CHARSUB(patinstart, *sp) +
patoffset +
!isset(KSHARRAYS)));
mbeginarr[i] = ztrdup(numbuf);
sprintf(numbuf, "%ld",
(long)(CHARSUB(patinstart, *ep) +
patoffset +
!isset(KSHARRAYS) - 1));
mendarr[i] = ztrdup(numbuf);
} else {
matcharr[i] = ztrdup("");
mbeginarr[i] = ztrdup("-1");
mendarr[i] = ztrdup("-1");
}
sp++;
ep++;
}
setaparam("match", matcharr);
setaparam("mbegin", mbeginarr);
setaparam("mend", mendarr);
}
if (!nump && endp) {
*endp = CHARSUB(patinstart, patinput) + patoffset;
}
ret = 1;
} else
ret = 0;
if (tryalloced)
zfree(tryalloced, unmetalen + unmetalenp);
return ret;
}
}
int
patmatchlen(void)
{
return patinlen;
}
#ifdef MULTIBYTE_SUPPORT
#define ISUPPER(x) iswupper(x)
#define ISLOWER(x) iswlower(x)
#define TOUPPER(x) towupper(x)
#define TOLOWER(x) towlower(x)
#define ISDIGIT(x) iswdigit(x)
#else
#define ISUPPER(x) isupper(x)
#define ISLOWER(x) islower(x)
#define TOUPPER(x) toupper(x)
#define TOLOWER(x) tolower(x)
#define ISDIGIT(x) idigit(x)
#endif
#define CHARMATCH(chin, chpa) (chin == chpa || \
((patglobflags & GF_IGNCASE) ? \
((ISUPPER(chin) ? TOLOWER(chin) : chin) == \
(ISUPPER(chpa) ? TOLOWER(chpa) : chpa)) : \
(patglobflags & GF_LCMATCHUC) ? \
(ISLOWER(chpa) && TOUPPER(chpa) == chin) : 0))
#define CHARMATCH_EXPR(expr, chpa) \
(charmatch_cache = (expr), CHARMATCH(charmatch_cache, chpa))
static char *exactpos, *exactend;
static int
patmatch(Upat prog)
{
Upat scan = prog, next, opnd;
char *start, *save, *chrop, *chrend, *compend;
int savglobflags, op, no, min, fail = 0, saverrsfound;
zrange_t from, to, comp;
patint_t nextch;
while (scan) {
next = PATNEXT(scan);
if (!globdots && P_NOTDOT(scan) && patinput == patinstart &&
patinput < patinend && *patinput == '.')
return 0;
switch (P_OP(scan)) {
case P_ANY:
if (patinput == patinend)
fail = 1;
else
CHARINC(patinput, patinend);
break;
case P_EXACTLY:
if (exactpos) {
chrop = exactpos;
chrend = exactend;
} else {
chrop = P_LS_STR(scan);
chrend = chrop + P_LS_LEN(scan);
}
exactpos = NULL;
while (chrop < chrend && patinput < patinend) {
char *savpatinput = patinput;
char *savchrop = chrop;
patint_t chin = CHARREFINC(patinput, patinend);
patint_t chpa = CHARREFINC(chrop, chrend);
if (!CHARMATCH(chin, chpa)) {
fail = 1;
patinput = savpatinput;
chrop = savchrop;
break;
}
}
if (chrop < chrend) {
exactpos = chrop;
exactend = chrend;
fail = 1;
}
break;
case P_ANYOF:
case P_ANYBUT:
if (patinput == patinend)
fail = 1;
else {
#ifdef MULTIBYTE_SUPPORT
wchar_t cr = CHARREF(patinput, patinend);
char *scanop = (char *)P_OPERAND(scan);
if (patglobflags & GF_MULTIBYTE) {
if (mb_patmatchrange(scanop, cr, NULL, NULL) ^
(P_OP(scan) == P_ANYOF))
fail = 1;
else
CHARINC(patinput, patinend);
} else if (patmatchrange(scanop, (int)cr, NULL, NULL) ^
(P_OP(scan) == P_ANYOF))
fail = 1;
else
CHARINC(patinput, patinend);
#else
if (patmatchrange((char *)P_OPERAND(scan),
CHARREF(patinput, patinend), NULL, NULL) ^
(P_OP(scan) == P_ANYOF))
fail = 1;
else
CHARINC(patinput, patinend);
#endif
}
break;
case P_NUMRNG:
case P_NUMFROM:
case P_NUMTO:
op = P_OP(scan);
start = (char *)P_OPERAND(scan);
from = to = 0;
if (op != P_NUMTO) {
#ifdef ZSH_64_BIT_TYPE
memcpy((char *)&from, start, sizeof(zrange_t));
#else
from = *((zrange_t *) start);
#endif
start += sizeof(zrange_t);
}
if (op != P_NUMFROM) {
#ifdef ZSH_64_BIT_TYPE
memcpy((char *)&to, start, sizeof(zrange_t));
#else
to = *((zrange_t *) start);
#endif
}
start = compend = patinput;
comp = 0;
while (patinput < patinend && idigit(*patinput)) {
if (comp)
comp *= 10;
comp += *patinput - '0';
patinput++;
compend++;
if (comp & ((zrange_t)1 << (sizeof(comp)*8 -
#ifdef ZRANGE_T_IS_SIGNED
2
#else
1
#endif
))) {
if (op == P_NUMFROM) {
while (patinput < patinend && idigit(*patinput))
patinput++;
}
}
}
save = patinput;
no = 0;
while (patinput > start) {
if (comp < from && patinput <= compend)
break;
if ((op == P_NUMFROM || comp <= to) && patmatch(next)) {
return 1;
}
if (!no && P_OP(next) == P_EXACTLY &&
(!P_LS_LEN(next) ||
!idigit(STOUC(*P_LS_STR(next)))) &&
!(patglobflags & 0xff))
return 0;
patinput = --save;
no++;
if (patinput < compend)
comp /= 10;
}
patinput = start;
fail = 1;
break;
case P_NUMANY:
start = patinput;
while (patinput < patinend && idigit(*patinput))
patinput++;
save = patinput;
no = 0;
while (patinput > start) {
if (patmatch(next))
return 1;
if (!no && P_OP(next) == P_EXACTLY &&
(!P_LS_LEN(next) ||
!idigit(*P_LS_STR(next))) &&
!(patglobflags & 0xff))
return 0;
patinput = --save;
no++;
}
patinput = start;
fail = 1;
break;
case P_NOTHING:
break;
case P_BACK:
break;
case P_GFLAGS:
patglobflags = P_OPERAND(scan)->l;
break;
case P_OPEN:
case P_OPEN+1:
case P_OPEN+2:
case P_OPEN+3:
case P_OPEN+4:
case P_OPEN+5:
case P_OPEN+6:
case P_OPEN+7:
case P_OPEN+8:
case P_OPEN+9:
no = P_OP(scan) - P_OPEN;
save = patinput;
if (patmatch(next)) {
if (no && !(parsfound & (1 << (no - 1)))) {
patbeginp[no-1] = save;
parsfound |= 1 << (no - 1);
}
return 1;
} else
return 0;
break;
case P_CLOSE:
case P_CLOSE+1:
case P_CLOSE+2:
case P_CLOSE+3:
case P_CLOSE+4:
case P_CLOSE+5:
case P_CLOSE+6:
case P_CLOSE+7:
case P_CLOSE+8:
case P_CLOSE+9:
no = P_OP(scan) - P_CLOSE;
save = patinput;
if (patmatch(next)) {
if (no && !(parsfound & (1 << (no + 15)))) {
patendp[no-1] = save;
parsfound |= 1 << (no + 15);
}
return 1;
} else
return 0;
break;
case P_EXCSYNC:
{
unsigned char *syncptr;
Upat after;
after = P_OPERAND(scan);
DPUTS(!P_ISEXCLUDE(after),
"BUG: EXCSYNC not followed by EXCLUDE.");
DPUTS(!P_OPERAND(after)->p,
"BUG: EXCSYNC not handled by EXCLUDE");
syncptr = P_OPERAND(after)->p + (patinput - patinstart);
if (*syncptr && errsfound + 1 >= *syncptr)
return 0;
*syncptr = errsfound + 1;
}
break;
case P_EXCEND:
if (!(fail = (patinput < patinend)))
return 1;
break;
case P_BRANCH:
case P_WBRANCH:
if (!P_ISBRANCH(next)) {
DPUTS(P_OP(scan) == P_WBRANCH,
"BUG: WBRANCH with no alternative.");
next = P_OPERAND(scan);
} else {
do {
save = patinput;
savglobflags = patglobflags;
saverrsfound = errsfound;
if (P_ISEXCLUDE(next)) {
Upat syncstrp;
char *origpatinend;
unsigned char *oldsyncstr;
char *matchpt = NULL;
int ret, savglobdots, matchederrs = 0;
int savparsfound = parsfound;
DPUTS(P_OP(scan) == P_WBRANCH,
"BUG: excluded WBRANCH");
syncstrp = P_OPERAND(next);
oldsyncstr = syncstrp->p;
syncstrp->p = (unsigned char *)
zshcalloc((patinend - patinstart) + 1);
origpatinend = patinend;
while ((ret = patmatch(P_OPERAND(scan)))) {
unsigned char *syncpt;
char *savpatinstart;
int savforce = forceerrs;
int savpatflags = patflags, synclen;
forceerrs = -1;
savglobdots = globdots;
matchederrs = errsfound;
matchpt = patinput;
globdots = 1;
for (syncpt = syncstrp->p; !*syncpt; syncpt++)
;
synclen = syncpt - syncstrp->p;
if (patinstart + synclen != patinend) {
DPUTS(patinstart + synclen > matchpt,
"BUG: EXCSYNC failed");
patinend = patinstart + synclen;
patflags |= PAT_NOTEND;
}
savpatinstart = patinstart;
next = PATNEXT(scan);
while (next && P_ISEXCLUDE(next)) {
patinput = save;
patglobflags &= ~0xff;
errsfound = 0;
opnd = P_OPERAND(next) + 1;
if (P_OP(next) == P_EXCLUDP && patinpath) {
DPUTS(patinput != patinstart,
"BUG: not at start excluding path");
patinput = patinstart = patinpath;
}
if (patmatch(opnd)) {
ret = 0;
parsfound = savparsfound;
}
if (patinpath) {
patinput = savpatinstart +
(patinput - patinstart);
patinstart = savpatinstart;
}
if (!ret)
break;
next = PATNEXT(next);
}
patinend = origpatinend;
patflags = savpatflags;
globdots = savglobdots;
forceerrs = savforce;
if (ret)
break;
patinput = save;
patglobflags = savglobflags;
errsfound = saverrsfound;
}
zfree((char *)syncstrp->p,
(patinend - patinstart) + 1);
syncstrp->p = oldsyncstr;
if (ret) {
patinput = matchpt;
errsfound = matchederrs;
return 1;
}
while ((scan = PATNEXT(scan)) &&
P_ISEXCLUDE(scan))
;
} else {
int ret = 1, pfree = 0;
Upat ptrp = NULL;
unsigned char *ptr;
if (P_OP(scan) == P_WBRANCH) {
opnd = P_OPERAND(scan);
ptrp = opnd++;
if (!ptrp->p) {
ptrp->p = (unsigned char *)
zshcalloc((patinend - patinstart) + 1);
pfree = 1;
}
ptr = ptrp->p + (patinput - patinstart);
if (*ptr && errsfound + 1 >= *ptr)
ret = 0;
*ptr = errsfound + 1;
} else
opnd = P_OPERAND(scan);
if (ret)
ret = patmatch(opnd);
if (pfree) {
zfree((char *)ptrp->p,
(patinend - patinstart) + 1);
ptrp->p = NULL;
}
if (ret)
return 1;
scan = PATNEXT(scan);
}
patinput = save;
patglobflags = savglobflags;
errsfound = saverrsfound;
DPUTS(P_OP(scan) == P_WBRANCH,
"BUG: WBRANCH not first choice.");
next = PATNEXT(scan);
} while (scan && P_ISBRANCH(scan));
return 0;
}
break;
case P_STAR:
case P_ONEHASH:
case P_TWOHASH:
op = P_OP(scan);
start = patinput;
{
char *lastcharstart;
VARARR(char, charstart, patinend-patinput);
memset(charstart, 0, patinend-patinput);
if (op == P_STAR) {
for (no = 0; patinput < patinend;
CHARINC(patinput, patinend))
{
charstart[patinput-start] = 1;
no++;
}
if (P_OP(next) == P_END)
return 1;
} else {
DPUTS(patglobflags & 0xff,
"BUG: wrong backtracking with approximation.");
if (!globdots && P_NOTDOT(P_OPERAND(scan)) &&
patinput == patinstart && patinput < patinend &&
CHARREF(patinput, patinend) == ZWC('.'))
return 0;
no = patrepeat(P_OPERAND(scan), charstart);
}
min = (op == P_TWOHASH) ? 1 : 0;
if (P_OP(next) == P_EXACTLY && P_LS_LEN(next) &&
!(patglobflags & 0xff)) {
char *nextop = P_LS_STR(next);
#ifdef MULTIBYTE_SUPPORT
int nextlen = P_LS_LEN(next);
#endif
if (P_OP(PATNEXT(next)) == P_END &&
!(patflags & PAT_NOANCH)) {
int ptlen = patinend - patinput;
int lenmatch = patinend -
(min ? CHARNEXT(start, patinend) : start);
if (P_LS_LEN(next) > lenmatch ||
P_LS_LEN(next) < ptlen)
return 0;
patinput += ptlen - P_LS_LEN(next);
break;
}
nextch = CHARREF(nextop, nextop + nextlen);
} else
nextch = PEOF;
savglobflags = patglobflags;
saverrsfound = errsfound;
lastcharstart = charstart + (patinput - start);
if (no >= min) {
for (;;) {
patint_t charmatch_cache;
if (nextch == PEOF ||
(patinput < patinend &&
CHARMATCH_EXPR(CHARREF(patinput, patinend),
nextch))) {
if (patmatch(next))
return 1;
}
if (--no < min)
break;
while (!*--lastcharstart)
DPUTS(lastcharstart < charstart,
"lastcharstart invalid");
patinput = start + (lastcharstart-charstart);
patglobflags = savglobflags;
errsfound = saverrsfound;
}
}
}
return 0;
case P_ISSTART:
if (patinput != patinstart || (patflags & PAT_NOTSTART))
fail = 1;
break;
case P_ISEND:
if (patinput < patinend || (patflags & PAT_NOTEND))
fail = 1;
break;
case P_COUNTSTART:
{
long *curptr = &P_OPERAND(scan)[P_CT_CURRENT].l;
long savecount = *curptr;
unsigned char *saveptr = scan[P_CT_PTR].p;
int ret;
*curptr = 0L;
ret = patmatch(P_OPERAND(scan));
*curptr = savecount;
scan[P_CT_PTR].p = saveptr;
return ret;
}
case P_COUNT:
{
long cur = scan[P_CT_CURRENT].l;
long min = scan[P_CT_MIN].l;
long max = scan[P_CT_MAX].l;
if (cur && cur >= min &&
(unsigned char *)patinput == scan[P_CT_PTR].p) {
return patmatch(next);
}
scan[P_CT_PTR].p = (unsigned char *)patinput;
if (max < 0 || cur < max) {
char *patinput_thistime = patinput;
scan[P_CT_CURRENT].l = cur + 1;
if (patmatch(scan + P_CT_OPERAND))
return 1;
patinput = patinput_thistime;
}
if (cur < min)
return 0;
return patmatch(next);
}
case P_END:
if (!(fail = (patinput < patinend && !(patflags & PAT_NOANCH))))
return 1;
break;
#ifdef DEBUG
default:
dputs("BUG: bad operand in patmatch.");
return 0;
break;
#endif
}
if (fail) {
if (errsfound < (patglobflags & 0xff) &&
(forceerrs == -1 || errsfound < forceerrs)) {
char *savexact = exactpos;
save = patinput;
savglobflags = patglobflags;
saverrsfound = ++errsfound;
fail = 0;
DPUTS(P_OP(scan) != P_EXACTLY && exactpos,
"BUG: non-exact match has set exactpos");
if (patinput < patinend) {
CHARINC(patinput, patinend);
if (P_OP(scan) != P_EXACTLY)
continue;
if (patmatch(scan))
return 1;
}
if (P_OP(scan) == P_EXACTLY) {
char *nextexact = savexact;
DPUTS(!savexact,
"BUG: exact match has not set exactpos");
CHARINC(nextexact, exactend);
if (save < patinend) {
char *nextin = save;
CHARINC(nextin, patinend);
patglobflags = savglobflags;
errsfound = saverrsfound;
exactpos = savexact;
if (save < patinend && nextin < patinend &&
nextexact < exactend) {
patint_t cin0 = CHARREF(save, patinend);
patint_t cpa0 = CHARREF(exactpos, exactend);
patint_t cin1 = CHARREF(nextin, patinend);
patint_t cpa1 = CHARREF(nextexact, exactend);
if (CHARMATCH(cin0, cpa1) &&
CHARMATCH(cin1, cpa0)) {
patinput = nextin;
CHARINC(patinput, patinend);
exactpos = nextexact;
CHARINC(exactpos, exactend);
if (patmatch(scan))
return 1;
patglobflags = savglobflags;
errsfound = saverrsfound;
}
}
patinput = nextin;
exactpos = nextexact;
if (patmatch(scan))
return 1;
patinput = save;
patglobflags = savglobflags;
errsfound = saverrsfound;
exactpos = savexact;
}
DPUTS(exactpos == exactend, "approximating too far");
CHARINC(exactpos, exactend);
continue;
}
}
exactpos = NULL;
return 0;
}
scan = next;
}
return 0;
}
#ifdef MULTIBYTE_SUPPORT
mod_export int
mb_patmatchrange(char *range, wchar_t ch, wint_t *indptr, int *mtp)
{
wchar_t r1, r2;
if (indptr)
*indptr = 0;
while (*range) {
if (imeta(STOUC(*range))) {
int swtype = STOUC(*range++) - STOUC(Meta);
if (mtp)
*mtp = swtype;
switch (swtype) {
case 0:
range--;
if (metacharinc(&range) == ch)
return 1;
break;
case PP_ALPHA:
if (iswalpha(ch))
return 1;
break;
case PP_ALNUM:
if (iswalnum(ch))
return 1;
break;
case PP_ASCII:
if ((ch & ~0x7f) == 0)
return 1;
break;
case PP_BLANK:
if (ch == L' ' || ch == L'\t')
return 1;
break;
case PP_CNTRL:
if (iswcntrl(ch))
return 1;
break;
case PP_DIGIT:
if (iswdigit(ch))
return 1;
break;
case PP_GRAPH:
if (iswgraph(ch))
return 1;
break;
case PP_LOWER:
if (iswlower(ch))
return 1;
break;
case PP_PRINT:
if (iswprint(ch))
return 1;
break;
case PP_PUNCT:
if (iswpunct(ch))
return 1;
break;
case PP_SPACE:
if (iswspace(ch))
return 1;
break;
case PP_UPPER:
if (iswupper(ch))
return 1;
break;
case PP_XDIGIT:
if (iswxdigit(ch))
return 1;
break;
case PP_IDENT:
if (wcsitype(ch, IIDENT))
return 1;
break;
case PP_IFS:
if (wcsitype(ch, ISEP))
return 1;
break;
case PP_IFSSPACE:
if (ch < 128 && iwsep((int)ch))
return 1;
break;
case PP_WORD:
if (wcsitype(ch, IWORD))
return 1;
break;
case PP_RANGE:
r1 = metacharinc(&range);
r2 = metacharinc(&range);
if (r1 <= ch && ch <= r2) {
if (indptr)
*indptr += ch - r1;
return 1;
}
if (indptr && r1 < r2) {
*indptr += r2 - r1;
}
break;
case PP_UNKWN:
DPUTS(1, "BUG: unknown posix range passed through.\n");
break;
default:
DPUTS(1, "BUG: unknown metacharacter in range.");
break;
}
} else if (metacharinc(&range) == ch) {
if (mtp)
*mtp = 0;
return 1;
}
if (indptr)
(*indptr)++;
}
return 0;
}
#if 0
mod_export int
mb_patmatchindex(char *range, wint_t ind, wint_t *chr, int *mtp)
{
wchar_t r1, r2, rchr;
wint_t rdiff;
*chr = WEOF;
*mtp = 0;
while (*range) {
if (imeta(STOUC(*range))) {
int swtype = STOUC(*range++) - STOUC(Meta);
switch (swtype) {
case 0:
range--;
rchr = metacharinc(&range);
if (!ind) {
*chr = (wint_t) rchr;
return 1;
}
break;
case PP_ALPHA:
case PP_ALNUM:
case PP_ASCII:
case PP_BLANK:
case PP_CNTRL:
case PP_DIGIT:
case PP_GRAPH:
case PP_LOWER:
case PP_PRINT:
case PP_PUNCT:
case PP_SPACE:
case PP_UPPER:
case PP_XDIGIT:
case PP_IDENT:
case PP_IFS:
case PP_IFSSPACE:
case PP_WORD:
if (!ind) {
*mtp = swtype;
return 1;
}
break;
case PP_RANGE:
r1 = metacharinc(&range);
r2 = metacharinc(&range);
rdiff = (wint_t)r2 - (wint_t)r1;
if (rdiff >= ind) {
*chr = (wint_t)r1 + ind;
return 1;
}
ind -= rdiff;
break;
case PP_UNKWN:
DPUTS(1, "BUG: unknown posix range passed through.\n");
break;
default:
DPUTS(1, "BUG: unknown metacharacter in range.");
break;
}
} else {
rchr = metacharinc(&range);
if (!ind) {
*chr = (wint_t)rchr;
return 1;
}
}
if (!ind--)
break;
}
return 0;
}
#endif
#endif
mod_export int
patmatchrange(char *range, int ch, int *indptr, int *mtp)
{
int r1, r2;
if (indptr)
*indptr = 0;
for (; *range; range++) {
if (imeta(STOUC(*range))) {
int swtype = STOUC(*range) - STOUC(Meta);
if (mtp)
*mtp = swtype;
switch (swtype) {
case 0:
if (STOUC(*++range ^ 32) == ch)
return 1;
break;
case PP_ALPHA:
if (isalpha(ch))
return 1;
break;
case PP_ALNUM:
if (isalnum(ch))
return 1;
break;
case PP_ASCII:
if ((ch & ~0x7f) == 0)
return 1;
break;
case PP_BLANK:
if (ch == ' ' || ch == '\t')
return 1;
break;
case PP_CNTRL:
if (iscntrl(ch))
return 1;
break;
case PP_DIGIT:
if (isdigit(ch))
return 1;
break;
case PP_GRAPH:
if (isgraph(ch))
return 1;
break;
case PP_LOWER:
if (islower(ch))
return 1;
break;
case PP_PRINT:
if (isprint(ch))
return 1;
break;
case PP_PUNCT:
if (ispunct(ch))
return 1;
break;
case PP_SPACE:
if (isspace(ch))
return 1;
break;
case PP_UPPER:
if (isupper(ch))
return 1;
break;
case PP_XDIGIT:
if (isxdigit(ch))
return 1;
break;
case PP_IDENT:
if (iident(ch))
return 1;
break;
case PP_IFS:
if (isep(ch))
return 1;
break;
case PP_IFSSPACE:
if (iwsep(ch))
return 1;
break;
case PP_WORD:
if (iword(ch))
return 1;
break;
case PP_RANGE:
range++;
r1 = STOUC(UNMETA(range));
METACHARINC(range);
r2 = STOUC(UNMETA(range));
if (*range == Meta)
range++;
if (r1 <= ch && ch <= r2) {
if (indptr)
*indptr += ch - r1;
return 1;
}
if (indptr && r1 < r2)
*indptr += r2 - r1;
break;
case PP_UNKWN:
DPUTS(1, "BUG: unknown posix range passed through.\n");
break;
default:
DPUTS(1, "BUG: unknown metacharacter in range.");
break;
}
} else if (STOUC(*range) == ch) {
if (mtp)
*mtp = 0;
return 1;
}
if (indptr)
(*indptr)++;
}
return 0;
}
mod_export int
patmatchindex(char *range, int ind, int *chr, int *mtp)
{
int r1, r2, rdiff, rchr;
*chr = -1;
*mtp = 0;
for (; *range; range++) {
if (imeta(STOUC(*range))) {
int swtype = STOUC(*range) - STOUC(Meta);
switch (swtype) {
case 0:
rchr = STOUC(*++range) ^ 32;
if (!ind) {
*chr = rchr;
return 1;
}
break;
case PP_ALPHA:
case PP_ALNUM:
case PP_ASCII:
case PP_BLANK:
case PP_CNTRL:
case PP_DIGIT:
case PP_GRAPH:
case PP_LOWER:
case PP_PRINT:
case PP_PUNCT:
case PP_SPACE:
case PP_UPPER:
case PP_XDIGIT:
case PP_IDENT:
case PP_IFS:
case PP_IFSSPACE:
case PP_WORD:
if (!ind) {
*mtp = swtype;
return 1;
}
break;
case PP_RANGE:
range++;
r1 = STOUC(UNMETA(range));
METACHARINC(range);
r2 = STOUC(UNMETA(range));
if (*range == Meta)
range++;
rdiff = r2 - r1;
if (rdiff >= ind) {
*chr = r1 + ind;
return 1;
}
ind -= rdiff;
break;
case PP_UNKWN:
DPUTS(1, "BUG: unknown posix range passed through.\n");
break;
default:
DPUTS(1, "BUG: unknown metacharacter in range.");
break;
}
} else {
if (!ind) {
*chr = STOUC(*range);
return 1;
}
}
if (!ind--)
break;
}
return 0;
}
static int patrepeat(Upat p, char *charstart)
{
int count = 0;
patint_t tch, charmatch_cache;
char *scan, *opnd;
scan = patinput;
opnd = (char *)P_OPERAND(p);
switch(P_OP(p)) {
#ifdef DEBUG
case P_ANY:
dputs("BUG: ?# did not get optimized to *");
return 0;
break;
#endif
case P_EXACTLY:
DPUTS(P_LS_LEN(p) != 1, "closure following more than one character");
tch = CHARREF(P_LS_STR(p), P_LS_STR(p) + P_LS_LEN(p));
while (scan < patinend &&
CHARMATCH_EXPR(CHARREF(scan, patinend), tch)) {
charstart[scan-patinput] = 1;
count++;
CHARINC(scan, patinend);
}
break;
case P_ANYOF:
case P_ANYBUT:
while (scan < patinend) {
#ifdef MULTIBYTE_SUPPORT
wchar_t cr = CHARREF(scan, patinend);
if (patglobflags & GF_MULTIBYTE) {
if (mb_patmatchrange(opnd, cr, NULL, NULL) ^
(P_OP(p) == P_ANYOF))
break;
} else if (patmatchrange(opnd, (int)cr, NULL, NULL) ^
(P_OP(p) == P_ANYOF))
break;
#else
if (patmatchrange(opnd, CHARREF(scan, patinend), NULL, NULL) ^
(P_OP(p) == P_ANYOF))
break;
#endif
charstart[scan-patinput] = 1;
count++;
CHARINC(scan, patinend);
}
break;
#ifdef DEBUG
default:
dputs("BUG: something very strange is happening in patrepeat");
return 0;
break;
#endif
}
patinput = scan;
return count;
}
mod_export void
freepatprog(Patprog prog)
{
if (prog && prog != dummy_patprog1 && prog != dummy_patprog2)
zfree(prog, prog->size);
}