mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 03:44:55 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			694 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			694 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						||
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, 1},
 | 
						||
	{"search",	(PyCFunction)regobj_search, 1},
 | 
						||
	{"group",	(PyCFunction)regobj_group, 1},
 | 
						||
	{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",			     /*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 */
 | 
						||
	if (_PyString_Resize(&npattern, n - v) == 0)
 | 
						||
		return npattern;
 | 
						||
	else {
 | 
						||
		return NULL;
 | 
						||
	}
 | 
						||
 | 
						||
}
 | 
						||
 | 
						||
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_Parse(args, "(SS)", &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_Parse(args, "(SS)", &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_Parse(args, "i", &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, PyObject *args)
 | 
						||
{
 | 
						||
	if (!PyArg_Parse(args, ""))
 | 
						||
		return NULL;
 | 
						||
	return PyInt_FromLong((long)re_syntax);
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
static struct PyMethodDef regex_global_methods[] = {
 | 
						||
	{"compile",	regex_compile, 1},
 | 
						||
	{"symcomp",	regex_symcomp, 1},
 | 
						||
	{"match",	regex_match, 0},
 | 
						||
	{"search",	regex_search, 0},
 | 
						||
	{"set_syntax",	regex_set_syntax, 0},
 | 
						||
	{"get_syntax",  regex_get_syntax, 0},
 | 
						||
	{NULL,		NULL}		     /* sentinel */
 | 
						||
};
 | 
						||
 | 
						||
DL_EXPORT(void)
 | 
						||
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 */ ;
 | 
						||
}
 |