2 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
3 typedef int Py_ssize_t
;
4 #define PY_SSIZE_T_MAX INT_MAX
5 #define PY_SSIZE_T_MIN INT_MIN
9 ascii_escape_char(Py_UNICODE c
, char *output
, Py_ssize_t chars
);
11 ascii_escape_unicode(PyObject
*pystr
);
13 ascii_escape_str(PyObject
*pystr
);
15 py_encode_basestring_ascii(PyObject
* self
__attribute__((__unused__
)), PyObject
*pystr
);
16 void init_speedups(void);
18 #define S_CHAR(c) (c >= ' ' && c <= '~' && c != '\\' && c != '/' && c != '"')
20 #define MIN_EXPANSION 6
21 #ifdef Py_UNICODE_WIDE
22 #define MAX_EXPANSION (2 * MIN_EXPANSION)
24 #define MAX_EXPANSION MIN_EXPANSION
28 ascii_escape_char(Py_UNICODE c
, char *output
, Py_ssize_t chars
) {
30 output
[chars
++] = '\\';
32 case '/': output
[chars
++] = (char)c
; break;
33 case '\\': output
[chars
++] = (char)c
; break;
34 case '"': output
[chars
++] = (char)c
; break;
35 case '\b': output
[chars
++] = 'b'; break;
36 case '\f': output
[chars
++] = 'f'; break;
37 case '\n': output
[chars
++] = 'n'; break;
38 case '\r': output
[chars
++] = 'r'; break;
39 case '\t': output
[chars
++] = 't'; break;
41 #ifdef Py_UNICODE_WIDE
43 /* UTF-16 surrogate pair */
44 Py_UNICODE v
= c
- 0x10000;
45 c
= 0xd800 | ((v
>> 10) & 0x3ff);
46 output
[chars
++] = 'u';
47 x
= (c
& 0xf000) >> 12;
48 output
[chars
++] = (x
< 10) ? '0' + x
: 'a' + (x
- 10);
49 x
= (c
& 0x0f00) >> 8;
50 output
[chars
++] = (x
< 10) ? '0' + x
: 'a' + (x
- 10);
51 x
= (c
& 0x00f0) >> 4;
52 output
[chars
++] = (x
< 10) ? '0' + x
: 'a' + (x
- 10);
54 output
[chars
++] = (x
< 10) ? '0' + x
: 'a' + (x
- 10);
55 c
= 0xdc00 | (v
& 0x3ff);
56 output
[chars
++] = '\\';
59 output
[chars
++] = 'u';
60 x
= (c
& 0xf000) >> 12;
61 output
[chars
++] = (x
< 10) ? '0' + x
: 'a' + (x
- 10);
62 x
= (c
& 0x0f00) >> 8;
63 output
[chars
++] = (x
< 10) ? '0' + x
: 'a' + (x
- 10);
64 x
= (c
& 0x00f0) >> 4;
65 output
[chars
++] = (x
< 10) ? '0' + x
: 'a' + (x
- 10);
67 output
[chars
++] = (x
< 10) ? '0' + x
: 'a' + (x
- 10);
73 ascii_escape_unicode(PyObject
*pystr
) {
75 Py_ssize_t input_chars
;
76 Py_ssize_t output_size
;
80 Py_UNICODE
*input_unicode
;
82 input_chars
= PyUnicode_GET_SIZE(pystr
);
83 input_unicode
= PyUnicode_AS_UNICODE(pystr
);
84 /* One char input can be up to 6 chars output, estimate 4 of these */
85 output_size
= 2 + (MIN_EXPANSION
* 4) + input_chars
;
86 rval
= PyString_FromStringAndSize(NULL
, output_size
);
90 output
= PyString_AS_STRING(rval
);
92 output
[chars
++] = '"';
93 for (i
= 0; i
< input_chars
; i
++) {
94 Py_UNICODE c
= input_unicode
[i
];
96 output
[chars
++] = (char)c
;
98 chars
= ascii_escape_char(c
, output
, chars
);
100 if (output_size
- chars
< (1 + MAX_EXPANSION
)) {
101 /* There's more than four, so let's resize by a lot */
103 /* This is an upper bound */
104 if (output_size
> 2 + (input_chars
* MAX_EXPANSION
)) {
105 output_size
= 2 + (input_chars
* MAX_EXPANSION
);
107 if (_PyString_Resize(&rval
, output_size
) == -1) {
110 output
= PyString_AS_STRING(rval
);
113 output
[chars
++] = '"';
114 if (_PyString_Resize(&rval
, chars
) == -1) {
121 ascii_escape_str(PyObject
*pystr
) {
123 Py_ssize_t input_chars
;
124 Py_ssize_t output_size
;
130 input_chars
= PyString_GET_SIZE(pystr
);
131 input_str
= PyString_AS_STRING(pystr
);
132 /* One char input can be up to 6 chars output, estimate 4 of these */
133 output_size
= 2 + (MIN_EXPANSION
* 4) + input_chars
;
134 rval
= PyString_FromStringAndSize(NULL
, output_size
);
138 output
= PyString_AS_STRING(rval
);
140 output
[chars
++] = '"';
141 for (i
= 0; i
< input_chars
; i
++) {
142 Py_UNICODE c
= (Py_UNICODE
)input_str
[i
];
144 output
[chars
++] = (char)c
;
145 } else if (c
> 0x7F) {
146 /* We hit a non-ASCII character, bail to unicode mode */
149 uni
= PyUnicode_DecodeUTF8(input_str
, input_chars
, "strict");
153 rval
= ascii_escape_unicode(uni
);
157 chars
= ascii_escape_char(c
, output
, chars
);
159 /* An ASCII char can't possibly expand to a surrogate! */
160 if (output_size
- chars
< (1 + MIN_EXPANSION
)) {
161 /* There's more than four, so let's resize by a lot */
163 if (output_size
> 2 + (input_chars
* MIN_EXPANSION
)) {
164 output_size
= 2 + (input_chars
* MIN_EXPANSION
);
166 if (_PyString_Resize(&rval
, output_size
) == -1) {
169 output
= PyString_AS_STRING(rval
);
172 output
[chars
++] = '"';
173 if (_PyString_Resize(&rval
, chars
) == -1) {
179 PyDoc_STRVAR(pydoc_encode_basestring_ascii
,
180 "encode_basestring_ascii(basestring) -> str\n"
186 py_encode_basestring_ascii(PyObject
* self
__attribute__((__unused__
)), PyObject
*pystr
) {
188 if (PyString_Check(pystr
)) {
189 return ascii_escape_str(pystr
);
190 } else if (PyUnicode_Check(pystr
)) {
191 return ascii_escape_unicode(pystr
);
193 PyErr_SetString(PyExc_TypeError
, "first argument must be a string");
200 (PyCFunction)py_ ##n, \
204 static PyMethodDef speedups_methods
[] = {
205 DEFN(encode_basestring_ascii
, METH_O
),
214 m
= Py_InitModule4("_speedups", speedups_methods
, NULL
, NULL
, PYTHON_API_VERSION
);