self._silent = silent
self.current = current = {}
self.stack = [globals, initial, current]
+ self._push = self.stack.append
+ self._pop = self.stack.pop
self.globals = globals
self.initial = initial
"""
Pop the last layer from the stack and return it.
"""
- rv = self.stack.pop()
+ rv = self._pop()
self.current = self.stack[-1]
return rv
Push one layer to the stack. Layer must be a dict or omitted.
"""
data = data or {}
- self.stack.append(data)
+ self._push(data)
self.current = self.stack[-1]
return data
/* Set by init_constants to real values */
static PyObject *Undefined, *Deferred, *TemplateRuntimeError;
+static Py_UNICODE *amp, *lt, *gt, *qt;
/**
* Internal struct used by BaseContext to store the
Undefined = PyObject_GetAttrString(datastructure, "Undefined");
Deferred = PyObject_GetAttrString(datastructure, "Deferred");
TemplateRuntimeError = PyObject_GetAttrString(exceptions, "TemplateRuntimeError");
+
+ amp = ((PyUnicodeObject*)PyUnicode_DecodeASCII("&", 5, NULL))->str;
+ lt = ((PyUnicodeObject*)PyUnicode_DecodeASCII("<", 4, NULL))->str;
+ gt = ((PyUnicodeObject*)PyUnicode_DecodeASCII(">", 4, NULL))->str;
+ qt = ((PyUnicodeObject*)PyUnicode_DecodeASCII(""", 5, NULL))->str;
+
Py_DECREF(datastructure);
Py_DECREF(exceptions);
return 1;
}
+/**
+ * SGML/XML escape something.
+ *
+ * XXX: this is awefully slow for non unicode objects because they
+ * get converted to unicode first.
+ */
+static PyObject*
+escape(PyObject *self, PyObject *args)
+{
+ PyUnicodeObject *in, *out;
+ Py_UNICODE *outp;
+ int i, len;
+
+ int quotes = 0;
+ PyObject *text = NULL;
+
+ if (!PyArg_ParseTuple(args, "O|b", &text, "es))
+ return NULL;
+ in = (PyUnicodeObject*)PyObject_Unicode(text);
+ if (!in)
+ return NULL;
+
+ /* First we need to figure out how long the escaped string will be */
+ len = 0;
+ for (i = 0;i < in->length; i++) {
+ switch (in->str[i]) {
+ case '&':
+ len += 5;
+ break;
+ case '"':
+ len += quotes ? 5 : 1;
+ break;
+ case '<':
+ case '>':
+ len += 4;
+ break;
+ default:
+ len++;
+ }
+ }
+
+ /* Do we need to escape anything at all? */
+ if (len == in->length) {
+ Py_INCREF(in);
+ return (PyObject*)in;
+ }
+ out = (PyUnicodeObject*)PyUnicode_FromUnicode(NULL, len);
+ if (!out) {
+ return NULL;
+ }
+
+ outp = out->str;
+ for (i = 0;i < in->length; i++) {
+ switch (in->str[i]) {
+ case '&':
+ Py_UNICODE_COPY(outp, amp, 5);
+ outp += 5;
+ break;
+ case '"':
+ if (quotes) {
+ Py_UNICODE_COPY(outp, qt, 5);
+ outp += 5;
+ }
+ else
+ *outp++ = in->str[i];
+ break;
+ case '<':
+ Py_UNICODE_COPY(outp, lt, 4);
+ outp += 4;
+ break;
+ case '>':
+ Py_UNICODE_COPY(outp, gt, 4);
+ outp += 4;
+ break;
+ default:
+ *outp++ = in->str[i];
+ };
+ }
+
+ return (PyObject*)out;
+}
+
/**
* Deallocator for BaseContext.
*
};
static PyMethodDef module_methods[] = {
+ {"escape", (PyCFunction)escape, METH_VARARGS,
+ "escape(s, quotes=False) -> string\n\n"
+ "SGML/XML a string."},
{NULL, NULL, 0, NULL} /* Sentinel */
};
raise_syntax_error(e, self, source)
else:
# everything went well. attach the source and return it
- # attach the source for debugging
+ # the attached source is used by the traceback system for
+ # debugging porposes
rv._source = source
return rv
"""
Apply a list of filters on the variable.
"""
+ cache = context.cache
for key in filters:
- if key in context.cache:
- func = context.cache[key]
+ if key in cache:
+ func = cache[key]
else:
filtername, args = key
if filtername not in self.filters:
raise FilterNotFound(filtername)
- context.cache[key] = func = self.filters[filtername](*args)
+ cache[key] = func = self.filters[filtername](*args)
value = func(self, context, value)
return value
import re
import sys
import string
-import cgi
from types import MethodType, FunctionType
from compiler.ast import CallFunc, Name, Const
from jinja.nodes import Trans
#: used by from_string as cache
_from_string_env = None
-escape = cgi.escape
-
-
def urlize(text, trim_url_limit=None, nofollow=False):
"""
Converts any URLs in text into clickable links. Works on http://,
rv._mapping = deepcopy(self._mapping)
rv._queue = deepcopy(self._queue)
return rv
+
+
+# escaping function. Use this only if you escape unicode
+# objects. in all other cases it's likely that the cgi.escape
+# function performs better.
+try:
+ from jinja._speedups import escape
+except ImportError:
+ from cgi import escape