/* * regex.c * * This file is part of zsh, the Z shell. * * Copyright (c) 2007 Phil Pennock * All Rights Reserved. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and to distribute modified versions of this software for any * purpose, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * In no event shall Clint Adams or the Zsh Development Group be liable * to any party for direct, indirect, special, incidental, or consequential * damages arising out of the use of this software and its documentation, * even if Andrew Main and the Zsh Development Group have been advised of * the possibility of such damage. * * Clint Adams and the Zsh Development Group specifically disclaim any * warranties, including, but not limited to, the implied warranties of * merchantability and fitness for a particular purpose. The software * provided hereunder is on an "as is" basis, and Andrew Main and the * Zsh Development Group have no obligation to provide maintenance, * support, updates, enhancements, or modifications. * */ #include "regex.mdh" #include "regex.pro" #include /* we default to a vaguely modern syntax and set of capabilities */ #define ZREGEX_EXTENDED 0 /* if you want Basic syntax, make it an alternative options */ static void zregex_regerrwarn(int r, regex_t *re, char *msg) { char *errbuf; size_t errbufsz; errbufsz = regerror(r, re, NULL, 0); errbuf = zalloc(errbufsz*sizeof(char)); regerror(r, re, errbuf, errbufsz); zwarn("%s: %s", msg, errbuf); zfree(errbuf, errbufsz); } /**/ static int zcond_regex_match(char **a, int id) { regex_t re; regmatch_t *m, *matches = NULL; size_t matchessz; char *lhstr, *rhre, *s, **arr, **x; int r, n, return_value, rcflags, reflags, nelem, start; lhstr = cond_str(a,0,0); rhre = cond_str(a,1,0); rcflags = reflags = 0; return_value = 0; /* 1 => matched successfully */ switch(id) { case ZREGEX_EXTENDED: rcflags |= REG_EXTENDED; r = regcomp(&re, rhre, rcflags); if (r) { zregex_regerrwarn(r, &re, "failed to compile regex"); break; } /* re.re_nsub is number of parenthesized groups, we also need * 1 for the 0 offset, which is the entire matched portion */ matchessz = (re.re_nsub + 1) * sizeof(regmatch_t); matches = zalloc(matchessz); r = regexec(&re, lhstr, re.re_nsub+1, matches, reflags); if (r == REG_NOMATCH) /**/; else if (r == 0) { return_value = 1; if (isset(BASHREMATCH)) { start = 0; nelem = re.re_nsub + 1; } else { start = 1; nelem = re.re_nsub; } /* entire matched portion + re_nsub substrings + NULL */ if (nelem) { arr = x = (char **) zalloc(sizeof(char *) * (nelem + 1)); for (m = matches + start, n = start; n <= re.re_nsub; ++n, ++m, ++x) { *x = ztrduppfx(lhstr + m->rm_so, m->rm_eo - m->rm_so); } *x = NULL; } if (isset(BASHREMATCH)) { setaparam("BASH_REMATCH", arr); } else { m = matches; s = ztrduppfx(lhstr + m->rm_so, m->rm_eo - m->rm_so); setsparam("MATCH", s); if (nelem) setaparam("match", arr); } } else zregex_regerrwarn(r, &re, "regex matching error"); break; } if (matches) zfree(matches, matchessz); regfree(&re); return return_value; } static struct conddef cotab[] = { CONDDEF("regex-match", CONDF_INFIX, zcond_regex_match, 0, 0, ZREGEX_EXTENDED) }; /**/ int setup_(UNUSED(Module m)) { return 0; } /**/ int boot_(Module m) { return !addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)); } /**/ int cleanup_(Module m) { deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)); return 0; } /**/ int finish_(UNUSED(Module m)) { return 0; }