|
|
|
/*
|
|
|
|
XXX support range parameter on search
|
|
|
|
XXX support mstop parameter on search
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* Regular expression objects */
|
|
|
|
/* This uses Tatu Ylonen's copyleft-free reimplementation of
|
|
|
|
GNU regular expressions */
|
|
|
|
|
|
|
|
#include "Python.h"
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#include "regexpr.h"
|
|
|
|
|
|
|
|
static PyObject *RegexError; /* Exception */
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
PyObject_HEAD
|
|
|
|
struct re_pattern_buffer re_patbuf; /* The compiled expression */
|
|
|
|
struct re_registers re_regs; /* The registers from the last match */
|
|
|
|
char re_fastmap[256]; /* Storage for fastmap */
|
|
|
|
PyObject *re_translate; /* String object for translate table */
|
|
|
|
PyObject *re_lastok; /* String object last matched/searched */
|
|
|
|
PyObject *re_groupindex; /* Group name to index dictionary */
|
|
|
|
PyObject *re_givenpat; /* Pattern with symbolic groups */
|
|
|
|
PyObject *re_realpat; /* Pattern without symbolic groups */
|
|
|
|
} regexobject;
|
|
|
|
|
|
|
|
/* Regex object methods */
|
|
|
|
|
|
|
|
static void
|
|
|
|
reg_dealloc(regexobject *re)
|
|
|
|
{
|
|
|
|
if (re->re_patbuf.buffer)
|
|
|
|
free(re->re_patbuf.buffer);
|
|
|
|
Py_XDECREF(re->re_translate);
|
|
|
|
Py_XDECREF(re->re_lastok);
|
|
|
|
Py_XDECREF(re->re_groupindex);
|
|
|
|
Py_XDECREF(re->re_givenpat);
|
|
|
|
Py_XDECREF(re->re_realpat);
|
|
|
|
PyObject_Del(re);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
makeresult(struct re_registers *regs)
|
|
|
|
{
|
|
|
|
PyObject *v;
|
|
|
|
int i;
|
|
|
|
static PyObject *filler = NULL;
|
|
|
|
|
|
|
|
if (filler == NULL) {
|
|
|
|
filler = Py_BuildValue("(ii)", -1, -1);
|
|
|
|
if (filler == NULL)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
v = PyTuple_New(RE_NREGS);
|
|
|
|
if (v == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < RE_NREGS; i++) {
|
|
|
|
int lo = regs->start[i];
|
|
|
|
int hi = regs->end[i];
|
|
|
|
PyObject *w;
|
|
|
|
if (lo == -1 && hi == -1) {
|
|
|
|
w = filler;
|
|
|
|
Py_INCREF(w);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
w = Py_BuildValue("(ii)", lo, hi);
|
|
|
|
if (w == NULL || PyTuple_SetItem(v, i, w) < 0) {
|
|
|
|
Py_DECREF(v);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
regobj_match(regexobject *re, PyObject *args)
|
|
|
|
{
|
|
|
|
PyObject *argstring;
|
|
|
|
char *buffer;
|
|
|
|
int size;
|
|
|
|
int offset = 0;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "O|i:match", &argstring, &offset))
|
|
|
|
return NULL;
|
|
|
|
if (!PyArg_Parse(argstring, "t#", &buffer, &size))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (offset < 0 || offset > size) {
|
|
|
|
PyErr_SetString(RegexError, "match offset out of range");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
Py_XDECREF(re->re_lastok);
|
|
|
|
re->re_lastok = NULL;
|
|
|
|
result = _Py_re_match(&re->re_patbuf, (unsigned char *)buffer, size, offset,
|
|
|
|
&re->re_regs);
|
|
|
|
if (result < -1) {
|
|
|
|
/* Serious failure of some sort; if re_match didn't
|
|
|
|
set an exception, raise a generic error */
|
|
|
|
if (!PyErr_Occurred())
|
|
|
|
PyErr_SetString(RegexError, "match failure");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (result >= 0) {
|
|
|
|
Py_INCREF(argstring);
|
|
|
|
re->re_lastok = argstring;
|
|
|
|
}
|
|
|
|
return PyInt_FromLong((long)result); /* Length of the match or -1 */
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
regobj_search(regexobject *re, PyObject *args)
|
|
|
|
{
|
|
|
|
PyObject *argstring;
|
|
|
|
char *buffer;
|
|
|
|
int size;
|
|
|
|
int offset = 0;
|
|
|
|
int range;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "O|i:search", &argstring, &offset))
|
|
|
|
return NULL;
|
|
|
|
if (!PyArg_Parse(argstring, "t#:search", &buffer, &size))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (offset < 0 || offset > size) {
|
|
|
|
PyErr_SetString(RegexError, "search offset out of range");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* NB: In Emacs 18.57, the documentation for re_search[_2] and
|
|
|
|
the implementation don't match: the documentation states that
|
|
|
|
|range| positions are tried, while the code tries |range|+1
|
|
|
|
positions. It seems more productive to believe the code! */
|
|
|
|
range = size - offset;
|
|
|
|
Py_XDECREF(re->re_lastok);
|
|
|
|
re->re_lastok = NULL;
|
|
|
|
result = _Py_re_search(&re->re_patbuf, (unsigned char *)buffer, size, offset, range,
|
|
|
|
&re->re_regs);
|
|
|
|
if (result < -1) {
|
|
|
|
/* Serious failure of some sort; if re_match didn't
|
|
|
|
set an exception, raise a generic error */
|
|
|
|
if (!PyErr_Occurred())
|
|
|
|
PyErr_SetString(RegexError, "match failure");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (result >= 0) {
|
|
|
|
Py_INCREF(argstring);
|
|
|
|
re->re_lastok = argstring;
|
|
|
|
}
|
|
|
|
return PyInt_FromLong((long)result); /* Position of the match or -1 */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get the group from the regex where index can be a string (group name) or
|
|
|
|
an integer index [0 .. 99]
|
|
|
|
*/
|
|
|
|
static PyObject*
|
|
|
|
group_from_index(regexobject *re, PyObject *index)
|
|
|
|
{
|
|
|
|
int i, a, b;
|
|
|
|
char *v;
|
|
|
|
|
|
|
|
if (PyString_Check(index))
|
|
|
|
if (re->re_groupindex == NULL ||
|
|
|
|
!(index = PyDict_GetItem(re->re_groupindex, index)))
|
|
|
|
{
|
|
|
|
PyErr_SetString(RegexError,
|
|
|
|
"group() group name doesn't exist");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = PyInt_AsLong(index);
|
|
|
|
if (i == -1 && PyErr_Occurred())
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (i < 0 || i >= RE_NREGS) {
|
|
|
|
PyErr_SetString(RegexError, "group() index out of range");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (re->re_lastok == NULL) {
|
|
|
|
PyErr_SetString(RegexError,
|
|
|
|
"group() only valid after successful match/search");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
a = re->re_regs.start[i];
|
|
|
|
b = re->re_regs.end[i];
|
|
|
|
if (a < 0 || b < 0) {
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(v = PyString_AsString(re->re_lastok)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return PyString_FromStringAndSize(v+a, b-a);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
regobj_group(regexobject *re, PyObject *args)
|
|
|
|
{
|
|
|
|
int n = PyTuple_Size(args);
|
|
|
|
int i;
|
|
|
|
PyObject *res = NULL;
|
|
|
|
|
|
|
|
if (n < 0)
|
|
|
|
return NULL;
|
|
|
|
if (n == 0) {
|
|
|
|
PyErr_SetString(PyExc_TypeError, "not enough arguments");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (n == 1) {
|
|
|
|
/* return value is a single string */
|
|
|
|
PyObject *index = PyTuple_GetItem(args, 0);
|
|
|
|
if (!index)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return group_from_index(re, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return value is a tuple */
|
|
|
|
if (!(res = PyTuple_New(n)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
PyObject *index = PyTuple_GetItem(args, i);
|
|
|
|
PyObject *group = NULL;
|
|
|
|
|
|
|
|
if (!index)
|
|
|
|
goto finally;
|
|
|
|
if (!(group = group_from_index(re, index)))
|
|
|
|
goto finally;
|
|
|
|
if (PyTuple_SetItem(res, i, group) < 0)
|
|
|
|
goto finally;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
|
|
|
|
finally:
|
|
|
|
Py_DECREF(res);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct PyMethodDef reg_methods[] = {
|
|
|
|
{"match", (PyCFunction)regobj_match, METH_VARARGS},
|
|
|
|
{"search", (PyCFunction)regobj_search, METH_VARARGS},
|
|
|
|
{"group", (PyCFunction)regobj_group, METH_VARARGS},
|
|
|
|
{NULL, NULL} /* sentinel */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char* members[] = {
|
|
|
|
"last", "regs", "translate",
|
|
|
|
"groupindex", "realpat", "givenpat",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
regobj_getattr(regexobject *re, char *name)
|
|
|
|
{
|
|
|
|
if (strcmp(name, "regs") == 0) {
|
|
|
|
if (re->re_lastok == NULL) {
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
return makeresult(&re->re_regs);
|
|
|
|
}
|
|
|
|
if (strcmp(name, "last") == 0) {
|
|
|
|
if (re->re_lastok == NULL) {
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
Py_INCREF(re->re_lastok);
|
|
|
|
return re->re_lastok;
|
|
|
|
}
|
|
|
|
if (strcmp(name, "translate") == 0) {
|
|
|
|
if (re->re_translate == NULL) {
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
Py_INCREF(re->re_translate);
|
|
|
|
return re->re_translate;
|
|
|
|
}
|
|
|
|
if (strcmp(name, "groupindex") == 0) {
|
|
|
|
if (re->re_groupindex == NULL) {
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
Py_INCREF(re->re_groupindex);
|
|
|
|
return re->re_groupindex;
|
|
|
|
}
|
|
|
|
if (strcmp(name, "realpat") == 0) {
|
|
|
|
if (re->re_realpat == NULL) {
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
Py_INCREF(re->re_realpat);
|
|
|
|
return re->re_realpat;
|
|
|
|
}
|
|
|
|
if (strcmp(name, "givenpat") == 0) {
|
|
|
|
if (re->re_givenpat == NULL) {
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
Py_INCREF(re->re_givenpat);
|
|
|
|
return re->re_givenpat;
|
|
|
|
}
|
|
|
|
if (strcmp(name, "__members__") == 0) {
|
|
|
|
int i = 0;
|
|
|
|
PyObject *list = NULL;
|
|
|
|
|
|
|
|
/* okay, so it's unlikely this list will change that often.
|
|
|
|
still, it's easier to change it in just one place.
|
|
|
|
*/
|
|
|
|
while (members[i])
|
|
|
|
i++;
|
|
|
|
if (!(list = PyList_New(i)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
while (members[i]) {
|
|
|
|
PyObject* v = PyString_FromString(members[i]);
|
|
|
|
if (!v || PyList_SetItem(list, i, v) < 0) {
|
|
|
|
Py_DECREF(list);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
return Py_FindMethod(reg_methods, (PyObject *)re, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyTypeObject Regextype = {
|
|
|
|
PyObject_HEAD_INIT(NULL)
|
|
|
|
0, /*ob_size*/
|
|
|
|
"regex.regex", /*tp_name*/
|
|
|
|
sizeof(regexobject), /*tp_size*/
|
|
|
|
0, /*tp_itemsize*/
|
|
|
|
/* methods */
|
|
|
|
(destructor)reg_dealloc, /*tp_dealloc*/
|
|
|
|
0, /*tp_print*/
|
|
|
|
(getattrfunc)regobj_getattr, /*tp_getattr*/
|
|
|
|
0, /*tp_setattr*/
|
|
|
|
0, /*tp_compare*/
|
|
|
|
0, /*tp_repr*/
|
|
|
|
};
|
|
|
|
|
|
|
|
/* reference counting invariants:
|
|
|
|
pattern: borrowed
|
|
|
|
translate: borrowed
|
|
|
|
givenpat: borrowed
|
|
|
|
groupindex: transferred
|
|
|
|
*/
|
|
|
|
static PyObject *
|
|
|
|
newregexobject(PyObject *pattern, PyObject *translate, PyObject *givenpat, PyObject *groupindex)
|
|
|
|
{
|
|
|
|
regexobject *re;
|
|
|
|
char *pat;
|
|
|
|
int size;
|
|
|
|
|
|
|
|
if (!PyArg_Parse(pattern, "t#", &pat, &size))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (translate != NULL && PyString_Size(translate) != 256) {
|
|
|
|
PyErr_SetString(RegexError,
|
|
|
|
"translation table must be 256 bytes");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
re = PyObject_New(regexobject, &Regextype);
|
|
|
|
if (re != NULL) {
|
|
|
|
char *error;
|
|
|
|
re->re_patbuf.buffer = NULL;
|
|
|
|
re->re_patbuf.allocated = 0;
|
|
|
|
re->re_patbuf.fastmap = (unsigned char *)re->re_fastmap;
|
|
|
|
if (translate) {
|
|
|
|
re->re_patbuf.translate = (unsigned char *)PyString_AsString(translate);
|
|
|
|
if (!re->re_patbuf.translate)
|
|
|
|
goto finally;
|
|
|
|
Py_INCREF(translate);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
re->re_patbuf.translate = NULL;
|
|
|
|
re->re_translate = translate;
|
|
|
|
re->re_lastok = NULL;
|
|
|
|
re->re_groupindex = groupindex;
|
|
|
|
Py_INCREF(pattern);
|
|
|
|
re->re_realpat = pattern;
|
|
|
|
Py_INCREF(givenpat);
|
|
|
|
re->re_givenpat = givenpat;
|
|
|
|
error = _Py_re_compile_pattern((unsigned char *)pat, size, &re->re_patbuf);
|
|
|
|
if (error != NULL) {
|
|
|
|
PyErr_SetString(RegexError, error);
|
|
|
|
goto finally;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (PyObject *)re;
|
|
|
|
finally:
|
|
|
|
Py_DECREF(re);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
regex_compile(PyObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
PyObject *pat = NULL;
|
|
|
|
PyObject *tran = NULL;
|
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "S|S:compile", &pat, &tran))
|
|
|
|
return NULL;
|
|
|
|
return newregexobject(pat, tran, pat, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
symcomp(PyObject *pattern, PyObject *gdict)
|
|
|
|
{
|
|
|
|
char *opat, *oend, *o, *n, *g, *v;
|
|
|
|
int group_count = 0;
|
|
|
|
int sz;
|
|
|
|
int escaped = 0;
|
|
|
|
char name_buf[128];
|
|
|
|
PyObject *npattern;
|
|
|
|
int require_escape = re_syntax & RE_NO_BK_PARENS ? 0 : 1;
|
|
|
|
|
|
|
|
if (!(opat = PyString_AsString(pattern)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if ((sz = PyString_Size(pattern)) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
oend = opat + sz;
|
|
|
|
o = opat;
|
|
|
|
|
|
|
|
if (oend == opat) {
|
|
|
|
Py_INCREF(pattern);
|
|
|
|
return pattern;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(npattern = PyString_FromStringAndSize((char*)NULL, sz)) ||
|
|
|
|
!(n = PyString_AsString(npattern)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
while (o < oend) {
|
|
|
|
if (*o == '(' && escaped == require_escape) {
|
|
|
|
char *backtrack;
|
|
|
|
escaped = 0;
|
|
|
|
++group_count;
|
|
|
|
*n++ = *o;
|
|
|
|
if (++o >= oend || *o != '<')
|
|
|
|
continue;
|
|
|
|
/* *o == '<' */
|
|
|
|
if (o+1 < oend && *(o+1) == '>')
|
|
|
|
continue;
|
|
|
|
backtrack = o;
|
|
|
|
g = name_buf;
|
|
|
|
for (++o; o < oend;) {
|
|
|
|
if (*o == '>') {
|
|
|
|
PyObject *group_name = NULL;
|
|
|
|
PyObject *group_index = NULL;
|
|
|
|
*g++ = '\0';
|
|
|
|
group_name = PyString_FromString(name_buf);
|
|
|
|
group_index = PyInt_FromLong(group_count);
|
|
|
|
if (group_name == NULL ||
|
|
|
|
group_index == NULL ||
|
|
|
|
PyDict_SetItem(gdict, group_name,
|
|
|
|
group_index) != 0)
|
|
|
|
{
|
|
|
|
Py_XDECREF(group_name);
|
|
|
|
Py_XDECREF(group_index);
|
|
|
|
Py_XDECREF(npattern);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
Py_DECREF(group_name);
|
|
|
|
Py_DECREF(group_index);
|
|
|
|
++o; /* eat the '>' */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!isalnum(Py_CHARMASK(*o)) && *o != '_') {
|
|
|
|
o = backtrack;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*g++ = *o++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (*o == '[' && !escaped) {
|
|
|
|
*n++ = *o;
|
|
|
|
++o; /* eat the char following '[' */
|
|
|
|
*n++ = *o;
|
|
|
|
while (o < oend && *o != ']') {
|
|
|
|
++o;
|
|
|
|
*n++ = *o;
|
|
|
|
}
|
|
|
|
if (o < oend)
|
|
|
|
++o;
|
|
|
|
}
|
|
|
|
else if (*o == '\\') {
|
|
|
|
escaped = 1;
|
|
|
|
*n++ = *o;
|
|
|
|
++o;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
escaped = 0;
|
|
|
|
*n++ = *o;
|
|
|
|
++o;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(v = PyString_AsString(npattern))) {
|
|
|
|
Py_DECREF(npattern);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* _PyString_Resize() decrements npattern on failure */
|
|
|
|
_PyString_Resize(&npattern, n - v);
|
|
|
|
return npattern;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
regex_symcomp(PyObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
PyObject *pattern;
|
|
|
|
PyObject *tran = NULL;
|
|
|
|
PyObject *gdict = NULL;
|
|
|
|
PyObject *npattern;
|
|
|
|
PyObject *retval = NULL;
|
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "S|S:symcomp", &pattern, &tran))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
gdict = PyDict_New();
|
|
|
|
if (gdict == NULL || (npattern = symcomp(pattern, gdict)) == NULL) {
|
|
|
|
Py_DECREF(gdict);
|
|
|
|
Py_DECREF(pattern);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
retval = newregexobject(npattern, tran, pattern, gdict);
|
|
|
|
Py_DECREF(npattern);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *cache_pat;
|
|
|
|
static PyObject *cache_prog;
|
|
|
|
|
|
|
|
static int
|
|
|
|
update_cache(PyObject *pat)
|
|
|
|
{
|
|
|
|
PyObject *tuple = Py_BuildValue("(O)", pat);
|
|
|
|
int status = 0;
|
|
|
|
|
|
|
|
if (!tuple)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (pat != cache_pat) {
|
|
|
|
Py_XDECREF(cache_pat);
|
|
|
|
cache_pat = NULL;
|
|
|
|
Py_XDECREF(cache_prog);
|
|
|
|
cache_prog = regex_compile((PyObject *)NULL, tuple);
|
|
|
|
if (cache_prog == NULL) {
|
|
|
|
status = -1;
|
|
|
|
goto finally;
|
|
|
|
}
|
|
|
|
cache_pat = pat;
|
|
|
|
Py_INCREF(cache_pat);
|
|
|
|
}
|
|
|
|
finally:
|
|
|
|
Py_DECREF(tuple);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
regex_match(PyObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
PyObject *pat, *string;
|
|
|
|
PyObject *tuple, *v;
|
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "SS:match", &pat, &string))
|
|
|
|
return NULL;
|
|
|
|
if (update_cache(pat) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!(tuple = Py_BuildValue("(S)", string)))
|
|
|
|
return NULL;
|
|
|
|
v = regobj_match((regexobject *)cache_prog, tuple);
|
|
|
|
Py_DECREF(tuple);
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
regex_search(PyObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
PyObject *pat, *string;
|
|
|
|
PyObject *tuple, *v;
|
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "SS:search", &pat, &string))
|
|
|
|
return NULL;
|
|
|
|
if (update_cache(pat) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!(tuple = Py_BuildValue("(S)", string)))
|
|
|
|
return NULL;
|
|
|
|
v = regobj_search((regexobject *)cache_prog, tuple);
|
|
|
|
Py_DECREF(tuple);
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
regex_set_syntax(PyObject *self, PyObject *args)
|
|
|
|
{
|
|
|
|
int syntax;
|
|
|
|
if (!PyArg_ParseTuple(args, "i:set_syntax", &syntax))
|
|
|
|
return NULL;
|
|
|
|
syntax = re_set_syntax(syntax);
|
|
|
|
/* wipe the global pattern cache */
|
|
|
|
Py_XDECREF(cache_pat);
|
|
|
|
cache_pat = NULL;
|
|
|
|
Py_XDECREF(cache_prog);
|
|
|
|
cache_prog = NULL;
|
|
|
|
return PyInt_FromLong((long)syntax);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
regex_get_syntax(PyObject *self)
|
|
|
|
{
|
|
|
|
return PyInt_FromLong((long)re_syntax);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct PyMethodDef regex_global_methods[] = {
|
|
|
|
{"compile", regex_compile, METH_VARARGS},
|
|
|
|
{"symcomp", regex_symcomp, METH_VARARGS},
|
|
|
|
{"match", regex_match, METH_VARARGS},
|
|
|
|
{"search", regex_search, METH_VARARGS},
|
|
|
|
{"set_syntax", regex_set_syntax, METH_VARARGS},
|
|
|
|
{"get_syntax", (PyCFunction)regex_get_syntax, METH_NOARGS},
|
|
|
|
{NULL, NULL} /* sentinel */
|
|
|
|
};
|
|
|
|
|
|
|
|
PyMODINIT_FUNC
|
|
|
|
initregex(void)
|
|
|
|
{
|
|
|
|
PyObject *m, *d, *v;
|
|
|
|
int i;
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
/* Initialize object type */
|
|
|
|
Regextype.ob_type = &PyType_Type;
|
|
|
|
|
|
|
|
m = Py_InitModule("regex", regex_global_methods);
|
|
|
|
d = PyModule_GetDict(m);
|
|
|
|
|
|
|
|
if (PyErr_Warn(PyExc_DeprecationWarning,
|
|
|
|
"the regex module is deprecated; "
|
|
|
|
"please use the re module") < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Initialize regex.error exception */
|
|
|
|
v = RegexError = PyErr_NewException("regex.error", NULL, NULL);
|
|
|
|
if (v == NULL || PyDict_SetItemString(d, "error", v) != 0)
|
|
|
|
goto finally;
|
|
|
|
|
|
|
|
/* Initialize regex.casefold constant */
|
|
|
|
if (!(v = PyString_FromStringAndSize((char *)NULL, 256)))
|
|
|
|
goto finally;
|
|
|
|
|
|
|
|
if (!(s = PyString_AsString(v)))
|
|
|
|
goto finally;
|
|
|
|
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
|
|
if (isupper(i))
|
|
|
|
s[i] = tolower(i);
|
|
|
|
else
|
|
|
|
s[i] = i;
|
|
|
|
}
|
|
|
|
if (PyDict_SetItemString(d, "casefold", v) < 0)
|
|
|
|
goto finally;
|
|
|
|
Py_DECREF(v);
|
|
|
|
|
|
|
|
if (!PyErr_Occurred())
|
|
|
|
return;
|
|
|
|
finally:
|
|
|
|
/* Nothing */ ;
|
|
|
|
}
|