# /* * T 7 . C * * char * * rxgrep(string, pattern) * char *string; -- Where to search for it * char *pattern; -- What to search for * * Apply the regular expression (pattern[]) to the argument string[]. * Return 0 if it fails. If successful, return a pointer to the string. * that matched. Regular expressions are defined in rxcomp(). * * Globals unique to this routine are preceeded by "re_". */ #include #ifdef vms #include #define FALSE 0 #define TRUE 1 #endif #include "t.h" /* * The following must be identical in rxcomp(). */ #define CHAR 1 #define BOL 2 #define EOL 3 #define ANY 4 #define CLASS 5 #define NCLASS 6 #define STAR 7 #define PLUS 8 #define MINUS 9 #define ALPHA 10 #define DIGIT 11 #define NALPHA 12 #define PUNCT 13 #define CDIGIT 14 /* Not used in this version */ #define RANGE 15 #define ENDPAT 16 static char *re_string; /* Remember start loc. */ char * rxgrep(string, pattern) char *string; /* The string to look for */ char *pattern; /* Where to look for it */ /* * Match the string, return TRUE if it does. */ { register char *l; /* Line pointer */ char *re_pmatch(); re_string = string; for (l = string; *l; l++) { if (re_pmatch(l, string, pattern)) return(l); } return(NULL); } static char * re_pmatch(line, start, pattern) char *line; /* (partial) line to match */ char *start; /* Invariant line start */ char *pattern; /* (partial) pattern to match */ /* * Do the actual work of matching (recursively). Line is the current * piece of information to match. Start is the entire line -- as passed * to t_rxgrep(). This is needed for the :c scan. */ { register char *l; /* Current line pointer */ register char *p; /* Current pattern pointer */ register char c; /* Current character */ char *e; /* End for STAR and PLUS match */ int op; /* Pattern operation */ int n; /* Class counter */ char *are; /* Start of STAR match */ char *commapos; /* Comma position for :c match */ l = line; p = pattern; commapos = 0; while ((op = *p++) != ENDPAT) { switch(op) { case CHAR: if (tolower(*l++) != *p++) return(0); break; case BOL: if (l != re_string) return(0); break; case EOL: if (*l != '\0') return(0); break; case ANY: if (*l++ == '\0') return(0); break; case DIGIT: if ((c = *l++) < '0' || (c > '9')) return(0); break; case ALPHA: c = tolower(*l++); if (c < 'a' || c > 'z') return(0); break; case NALPHA: c = tolower(*l++); if (c >= 'a' && c <= 'z') break; else if (c < '0' || c > '9') return(0); break; case PUNCT: c = *l++; if (c == 0 || c > ' ') return(0); break; case CLASS: case NCLASS: c = tolower(*l++); n = *p++ & 0377; do { if (*p == RANGE) { p += 3; n -= 2; if (c >= p[-2] && c <= p[-1]) break; } else if (c == *p++) break; } while (--n > 1); if ((op == CLASS) == (n <= 1)) return(0); if (op == CLASS) p += n - 2; break; case MINUS: e = re_pmatch(l, start, p); while (*p++ != ENDPAT); /* Skip over pattern */ if (e) /* Got a match? */ l = e; /* Yes, update string */ break; /* Always succeeds */ case PLUS: /* One or more ... */ if ((l = re_pmatch(l, start, p)) == 0) return(0); /* Gotta have a match */ case STAR: /* Zero or more ... */ are = l; /* Remember line start */ while (*l && (e = re_pmatch(l, start, p))) l = e; /* Get longest match */ while (*p++ != ENDPAT); /* Skip over pattern */ while (l >= are) { /* Try to match rest */ if (e = re_pmatch(l, start, p)) return(e); --l; /* Nope, try earlier */ } return(0); /* Nothing else worked */ default: abort(); /* Illegal op code */ } } return(l); }