/src/cpython3/Parser/tokenizer/reader.c
Line | Count | Source |
1 | | #include "Python.h" |
2 | | #include "pycore_fileutils.h" |
3 | | |
4 | | #include "errcode.h" |
5 | | #include "helpers.h" |
6 | | #include "reader.h" |
7 | | #include "reader_internal.h" |
8 | | #include "../lexer/buffer.h" |
9 | | #include "../lexer/lexer.h" |
10 | | #include "../lexer/state.h" |
11 | | |
12 | | #ifdef HAVE_UNISTD_H |
13 | | # include <unistd.h> |
14 | | #endif |
15 | | |
16 | | void |
17 | | _PyTok_ReaderFree(struct tok_state *tok) |
18 | 24.5k | { |
19 | 24.5k | _PyTok_Reader *reader = tok->reader; |
20 | 24.5k | if (reader == NULL) { |
21 | 0 | return; |
22 | 0 | } |
23 | 24.5k | Py_XDECREF(reader->readline); |
24 | 24.5k | Py_XDECREF(reader->decoder); |
25 | 24.5k | for (int i = 0; |
26 | 73.7k | i < (int)Py_ARRAY_LENGTH(reader->prefetched_lines); i++) { |
27 | 49.1k | _PyTok_ChunkClear(&reader->prefetched_lines[i]); |
28 | 49.1k | } |
29 | 24.5k | PyMem_Free(reader->file_buffer); |
30 | 24.5k | PyMem_Free(reader->decoded); |
31 | 24.5k | if (reader->kind != _PYTOK_READER_PREPARED) { |
32 | 0 | PyMem_Free(tok->buf); |
33 | 0 | tok->buf = NULL; |
34 | 0 | } |
35 | 24.5k | PyMem_Free(reader); |
36 | 24.5k | tok->reader = NULL; |
37 | 24.5k | } |
38 | | |
39 | | static int |
40 | | reserve_buffer(char **buffer, Py_ssize_t *capacity, Py_ssize_t needed) |
41 | 0 | { |
42 | 0 | if (needed <= *capacity) { |
43 | 0 | return 0; |
44 | 0 | } |
45 | 0 | Py_ssize_t cap = *capacity > 0 ? *capacity : BUFSIZ; |
46 | 0 | while (cap < needed) { |
47 | 0 | if (cap > PY_SSIZE_T_MAX / 2) { |
48 | 0 | cap = needed; |
49 | 0 | break; |
50 | 0 | } |
51 | 0 | cap *= 2; |
52 | 0 | } |
53 | 0 | char *resized = PyMem_Realloc(*buffer, cap); |
54 | 0 | if (resized == NULL) { |
55 | 0 | PyErr_NoMemory(); |
56 | 0 | return -1; |
57 | 0 | } |
58 | 0 | *buffer = resized; |
59 | 0 | *capacity = cap; |
60 | 0 | return 0; |
61 | 0 | } |
62 | | |
63 | | static int |
64 | | append_decoded(_PyTok_Reader *reader, const char *data, Py_ssize_t len) |
65 | 0 | { |
66 | 0 | if (reader->decoded_pos > 0) { |
67 | 0 | Py_ssize_t remaining = reader->decoded_len - reader->decoded_pos; |
68 | 0 | memmove(reader->decoded, reader->decoded + reader->decoded_pos, |
69 | 0 | (size_t)remaining); |
70 | 0 | reader->decoded_pos = 0; |
71 | 0 | reader->decoded_len = remaining; |
72 | 0 | } |
73 | 0 | if (len < 0 || reader->decoded_len > PY_SSIZE_T_MAX - len - 1 || |
74 | 0 | reserve_buffer(&reader->decoded, &reader->decoded_cap, |
75 | 0 | reader->decoded_len + len + 1) < 0) { |
76 | 0 | PyErr_NoMemory(); |
77 | 0 | return -1; |
78 | 0 | } |
79 | 0 | memcpy(reader->decoded + reader->decoded_len, data, (size_t)len); |
80 | 0 | reader->decoded_len += len; |
81 | 0 | reader->decoded[reader->decoded_len] = '\0'; |
82 | 0 | return 0; |
83 | 0 | } |
84 | | |
85 | | static int |
86 | | append_implicit_newline(_PyTok_Reader *reader) |
87 | 0 | { |
88 | 0 | if (reader->decoded_pos == reader->decoded_len || |
89 | 0 | reader->decoded[reader->decoded_len - 1] == '\n') { |
90 | 0 | return 0; |
91 | 0 | } |
92 | 0 | if (append_decoded(reader, "\n", 1) < 0) { |
93 | 0 | return -1; |
94 | 0 | } |
95 | 0 | reader->decoded_tail_is_implicit = 1; |
96 | 0 | return 0; |
97 | 0 | } |
98 | | |
99 | | static int |
100 | | pop_decoded_line(_PyTok_Reader *reader, _PyTok_Chunk *chunk) |
101 | 0 | { |
102 | 0 | if (reader->decoded_pos == reader->decoded_len) { |
103 | 0 | return 0; |
104 | 0 | } |
105 | 0 | char *start = reader->decoded + reader->decoded_pos; |
106 | 0 | char *newline = memchr(start, '\n', |
107 | 0 | reader->decoded_len - reader->decoded_pos); |
108 | 0 | if (newline == NULL) { |
109 | 0 | return 0; |
110 | 0 | } |
111 | 0 | Py_ssize_t len = newline - start + 1; |
112 | 0 | chunk->data = start; |
113 | 0 | chunk->len = len; |
114 | 0 | chunk->ownership = _PYTOK_CHUNK_BORROWED; |
115 | 0 | reader->decoded_pos += len; |
116 | 0 | chunk->implicit_newline = reader->decoded_pos == reader->decoded_len && |
117 | 0 | reader->decoded_tail_is_implicit; |
118 | 0 | if (reader->decoded_pos == reader->decoded_len) { |
119 | 0 | reader->decoded_pos = reader->decoded_len = 0; |
120 | 0 | reader->decoded_tail_is_implicit = 0; |
121 | 0 | } |
122 | 0 | return 1; |
123 | 0 | } |
124 | | |
125 | | static int |
126 | | chunk_is_line(const _PyTok_Chunk *chunk) |
127 | 0 | { |
128 | 0 | if (chunk->len == 0 || chunk->data[chunk->len - 1] != '\n') { |
129 | 0 | return 0; |
130 | 0 | } |
131 | 0 | return memchr(chunk->data, '\n', chunk->len - 1) == NULL; |
132 | 0 | } |
133 | | |
134 | | static _PyTok_ReadResult |
135 | | next_prepared(struct tok_state *tok, _PyTok_Chunk *chunk) |
136 | 440k | { |
137 | 440k | int lineno = tok->lineno + 1; |
138 | 440k | if (lineno > tok->source.nlines) { |
139 | 19.4k | return _PYTOK_READ_EOF; |
140 | 19.4k | } |
141 | 421k | const char *start = tok->inp; |
142 | 421k | const char *newline = memchr( |
143 | 421k | start, '\n', tok->source.bytes + tok->source.len - start); |
144 | 421k | _PyTok_Off end = newline != NULL |
145 | 421k | ? newline - tok->source.bytes + 1 : tok->source.len; |
146 | 421k | chunk->data = (char *)start; |
147 | 421k | chunk->len = tok->source.bytes + end - start; |
148 | 421k | chunk->ownership = _PYTOK_CHUNK_BORROWED; |
149 | 421k | chunk->implicit_newline = _PyTok_SourceLineIsImplicit( |
150 | 421k | &tok->source, lineno); |
151 | 421k | return _PYTOK_READ_LINE; |
152 | 440k | } |
153 | | |
154 | | static _PyTok_ReadResult |
155 | | read_file_line(struct tok_state *tok, _PyTok_Chunk *chunk) |
156 | 0 | { |
157 | 0 | _PyTok_Reader *reader = tok->reader; |
158 | 0 | Py_ssize_t len = 0; |
159 | 0 | for (;;) { |
160 | 0 | if (len > PY_SSIZE_T_MAX - BUFSIZ || |
161 | 0 | reserve_buffer(&reader->file_buffer, &reader->file_buffer_cap, |
162 | 0 | len + BUFSIZ) < 0) { |
163 | 0 | return _PYTOK_READ_ERROR; |
164 | 0 | } |
165 | 0 | int available = (int)Py_MIN(reader->file_buffer_cap - len, INT_MAX); |
166 | 0 | size_t read = 0; |
167 | 0 | char *result = _Py_UniversalNewlineFgetsWithSize( |
168 | 0 | reader->file_buffer + len, available, tok->fp, NULL, &read); |
169 | 0 | if (result == NULL) { |
170 | 0 | if (len == 0) { |
171 | 0 | return _PYTOK_READ_EOF; |
172 | 0 | } |
173 | 0 | break; |
174 | 0 | } |
175 | 0 | len += (Py_ssize_t)read; |
176 | 0 | if (len > 0 && reader->file_buffer[len - 1] == '\n') { |
177 | 0 | break; |
178 | 0 | } |
179 | 0 | } |
180 | 0 | int implicit = len == 0 || reader->file_buffer[len - 1] != '\n'; |
181 | 0 | chunk->data = reader->file_buffer; |
182 | 0 | chunk->len = len; |
183 | 0 | chunk->implicit_newline = implicit; |
184 | 0 | chunk->ownership = _PYTOK_CHUNK_BORROWED; |
185 | 0 | return _PYTOK_READ_LINE; |
186 | 0 | } |
187 | | |
188 | | static int |
189 | | initialize_file(struct tok_state *tok) |
190 | 0 | { |
191 | 0 | _PyTok_Reader *reader = tok->reader; |
192 | 0 | reader->file_initialized = 1; |
193 | 0 | if (tok->encoding != NULL) { |
194 | 0 | return _PyTok_StartDecoder(tok, "strict"); |
195 | 0 | } |
196 | | |
197 | 0 | _PyTok_ReadResult result = read_file_line( |
198 | 0 | tok, &reader->prefetched_lines[0]); |
199 | 0 | if (result == _PYTOK_READ_EOF) { |
200 | 0 | reader->file_eof = 1; |
201 | 0 | return 0; |
202 | 0 | } |
203 | 0 | if (result != _PYTOK_READ_LINE) { |
204 | 0 | return -1; |
205 | 0 | } |
206 | 0 | reader->prefetched_count = 1; |
207 | 0 | Py_ssize_t bom_len; |
208 | 0 | _PyTok_EncodingResult detection = _PyTok_DetectEncoding( |
209 | 0 | tok, &reader->prefetched_lines[0], NULL, 0, &bom_len); |
210 | 0 | if (detection == _PYTOK_ENCODING_ERROR) { |
211 | 0 | return -1; |
212 | 0 | } |
213 | 0 | if (detection == _PYTOK_ENCODING_NEED_SECOND_LINE) { |
214 | 0 | char *first = _PyTok_CopyBytes( |
215 | 0 | reader->prefetched_lines[0].data, |
216 | 0 | reader->prefetched_lines[0].len); |
217 | 0 | if (first == NULL) { |
218 | 0 | tok->done = E_NOMEM; |
219 | 0 | return -1; |
220 | 0 | } |
221 | 0 | reader->prefetched_lines[0].data = first; |
222 | 0 | reader->prefetched_lines[0].ownership = _PYTOK_CHUNK_PYMEM; |
223 | 0 | result = read_file_line(tok, &reader->prefetched_lines[1]); |
224 | 0 | if (result == _PYTOK_READ_LINE) { |
225 | 0 | reader->prefetched_count = 2; |
226 | 0 | } |
227 | 0 | else if (result == _PYTOK_READ_EOF) { |
228 | 0 | reader->file_eof = 1; |
229 | 0 | } |
230 | 0 | else { |
231 | 0 | return -1; |
232 | 0 | } |
233 | 0 | _PyTok_Chunk *second = reader->prefetched_count == 2 |
234 | 0 | ? &reader->prefetched_lines[1] : NULL; |
235 | 0 | detection = _PyTok_DetectEncoding( |
236 | 0 | tok, &reader->prefetched_lines[0], second, 1, &bom_len); |
237 | 0 | if (detection == _PYTOK_ENCODING_ERROR) { |
238 | 0 | return -1; |
239 | 0 | } |
240 | 0 | } |
241 | 0 | if (bom_len != 0) { |
242 | 0 | _PyTok_Chunk *first = &reader->prefetched_lines[0]; |
243 | 0 | if (first->ownership == _PYTOK_CHUNK_PYMEM) { |
244 | 0 | memmove(first->data, first->data + bom_len, |
245 | 0 | (size_t)(first->len - bom_len)); |
246 | 0 | first->data[first->len - bom_len] = '\0'; |
247 | 0 | } |
248 | 0 | else { |
249 | 0 | first->data += bom_len; |
250 | 0 | } |
251 | 0 | first->len -= bom_len; |
252 | 0 | } |
253 | 0 | if (_PyTok_StartDecoder(tok, "strict") < 0) { |
254 | 0 | return -1; |
255 | 0 | } |
256 | 0 | return 0; |
257 | 0 | } |
258 | | |
259 | | static int |
260 | | finalize_decoding(struct tok_state *tok) |
261 | 0 | { |
262 | 0 | _PyTok_Reader *reader = tok->reader; |
263 | 0 | if (reader->decoder_finalized) { |
264 | 0 | return 0; |
265 | 0 | } |
266 | 0 | reader->decoder_finalized = 1; |
267 | 0 | if (reader->decoder != NULL) { |
268 | 0 | _PyTok_Chunk input = { |
269 | 0 | .data = "", |
270 | 0 | .ownership = _PYTOK_CHUNK_BORROWED, |
271 | 0 | }; |
272 | 0 | int decoded = _PyTok_DecodeChunk(tok, &input, 1); |
273 | 0 | if (decoded == 0 && |
274 | 0 | append_decoded(reader, input.data, input.len) < 0) { |
275 | 0 | tok->done = E_NOMEM; |
276 | 0 | decoded = -1; |
277 | 0 | } |
278 | 0 | _PyTok_ChunkClear(&input); |
279 | 0 | if (decoded < 0) { |
280 | 0 | return -1; |
281 | 0 | } |
282 | 0 | } |
283 | 0 | if (reader->decoded_pos < reader->decoded_len && |
284 | 0 | append_implicit_newline(reader) < 0) { |
285 | 0 | tok->done = E_NOMEM; |
286 | 0 | return -1; |
287 | 0 | } |
288 | 0 | return 0; |
289 | 0 | } |
290 | | |
291 | | static _PyTok_ReadResult |
292 | | next_file(struct tok_state *tok, _PyTok_Chunk *chunk) |
293 | 0 | { |
294 | 0 | _PyTok_Reader *reader = tok->reader; |
295 | 0 | if (!reader->file_initialized && initialize_file(tok) < 0) { |
296 | 0 | return _PYTOK_READ_ERROR; |
297 | 0 | } |
298 | 0 | for (;;) { |
299 | 0 | if (pop_decoded_line(reader, chunk)) { |
300 | 0 | return _PYTOK_READ_LINE; |
301 | 0 | } |
302 | 0 | _PyTok_Chunk input = {0}; |
303 | 0 | if (reader->prefetched_index < reader->prefetched_count) { |
304 | 0 | input = reader->prefetched_lines[reader->prefetched_index]; |
305 | 0 | reader->prefetched_lines[reader->prefetched_index++] = |
306 | 0 | (_PyTok_Chunk){0}; |
307 | 0 | } |
308 | 0 | else if (!reader->file_eof) { |
309 | 0 | _PyTok_ReadResult result = read_file_line(tok, &input); |
310 | 0 | if (result == _PYTOK_READ_ERROR) { |
311 | 0 | return result; |
312 | 0 | } |
313 | 0 | if (result == _PYTOK_READ_EOF) { |
314 | 0 | reader->file_eof = 1; |
315 | 0 | } |
316 | 0 | } |
317 | 0 | if (input.data != NULL) { |
318 | 0 | int implicit = input.implicit_newline; |
319 | 0 | if (reader->decoder == NULL && !implicit) { |
320 | 0 | *chunk = input; |
321 | 0 | return _PYTOK_READ_LINE; |
322 | 0 | } |
323 | 0 | int decoded = _PyTok_DecodeChunk(tok, &input, 0); |
324 | 0 | if (decoded == 0 && chunk_is_line(&input)) { |
325 | 0 | *chunk = input; |
326 | 0 | return _PYTOK_READ_LINE; |
327 | 0 | } |
328 | 0 | if (decoded == 0 && |
329 | 0 | append_decoded(reader, input.data, input.len) < 0) { |
330 | 0 | tok->done = E_NOMEM; |
331 | 0 | decoded = -1; |
332 | 0 | } |
333 | 0 | if (decoded == 0 && implicit) { |
334 | 0 | reader->decoded_tail_is_implicit = 1; |
335 | 0 | } |
336 | 0 | _PyTok_ChunkClear(&input); |
337 | 0 | if (decoded < 0) { |
338 | 0 | return _PYTOK_READ_ERROR; |
339 | 0 | } |
340 | 0 | continue; |
341 | 0 | } |
342 | 0 | if (!reader->decoder_finalized) { |
343 | 0 | if (finalize_decoding(tok) < 0) { |
344 | 0 | return _PYTOK_READ_ERROR; |
345 | 0 | } |
346 | 0 | continue; |
347 | 0 | } |
348 | 0 | return _PYTOK_READ_EOF; |
349 | 0 | } |
350 | 0 | } |
351 | | |
352 | | static _PyTok_ReadResult |
353 | | next_readline(struct tok_state *tok, _PyTok_Chunk *chunk) |
354 | 0 | { |
355 | 0 | _PyTok_Reader *reader = tok->reader; |
356 | 0 | for (;;) { |
357 | 0 | if (pop_decoded_line(reader, chunk)) { |
358 | 0 | return _PYTOK_READ_LINE; |
359 | 0 | } |
360 | 0 | if (reader->decoder_finalized) { |
361 | 0 | return _PYTOK_READ_EOF; |
362 | 0 | } |
363 | | |
364 | 0 | PyObject *raw = PyObject_CallNoArgs(reader->readline); |
365 | 0 | if (raw == NULL) { |
366 | 0 | if (PyErr_ExceptionMatches(PyExc_StopIteration)) { |
367 | 0 | PyErr_Clear(); |
368 | 0 | if (finalize_decoding(tok) < 0) { |
369 | 0 | return _PYTOK_READ_ERROR; |
370 | 0 | } |
371 | 0 | continue; |
372 | 0 | } |
373 | 0 | return _PYTOK_READ_ERROR; |
374 | 0 | } |
375 | | |
376 | 0 | _PyTok_Chunk input = {0}; |
377 | 0 | if (tok->encoding != NULL) { |
378 | 0 | if (!PyBytes_Check(raw)) { |
379 | 0 | PyErr_SetString(PyExc_TypeError, |
380 | 0 | "readline() returned a non-bytes object"); |
381 | 0 | Py_DECREF(raw); |
382 | 0 | return _PYTOK_READ_ERROR; |
383 | 0 | } |
384 | 0 | if (PyBytes_GET_SIZE(raw) == 0) { |
385 | 0 | Py_DECREF(raw); |
386 | 0 | if (_PyTok_StartDecoder(tok, "replace") < 0) { |
387 | 0 | return _PYTOK_READ_ERROR; |
388 | 0 | } |
389 | 0 | if (finalize_decoding(tok) < 0) { |
390 | 0 | return _PYTOK_READ_ERROR; |
391 | 0 | } |
392 | 0 | continue; |
393 | 0 | } |
394 | 0 | input.owner = raw; |
395 | 0 | input.data = PyBytes_AS_STRING(raw); |
396 | 0 | input.len = PyBytes_GET_SIZE(raw); |
397 | 0 | input.ownership = _PYTOK_CHUNK_PYOBJECT; |
398 | 0 | int decoded; |
399 | 0 | if (reader->decoder == NULL && |
400 | 0 | strcmp(tok->encoding, "utf-8") == 0 && |
401 | 0 | chunk_is_line(&input)) { |
402 | 0 | decoded = _PyTok_DecodeOnce( |
403 | 0 | tok, &input, "utf-8", "replace"); |
404 | 0 | } |
405 | 0 | else { |
406 | 0 | decoded = _PyTok_StartDecoder(tok, "replace"); |
407 | 0 | if (decoded == 0) { |
408 | 0 | decoded = _PyTok_DecodeChunk(tok, &input, 0); |
409 | 0 | } |
410 | 0 | } |
411 | 0 | if (decoded < 0) { |
412 | 0 | _PyTok_ChunkClear(&input); |
413 | 0 | return _PYTOK_READ_ERROR; |
414 | 0 | } |
415 | 0 | } |
416 | 0 | else { |
417 | 0 | if (!PyUnicode_Check(raw)) { |
418 | 0 | PyErr_SetString(PyExc_TypeError, |
419 | 0 | "readline() returned a non-string object"); |
420 | 0 | Py_DECREF(raw); |
421 | 0 | return _PYTOK_READ_ERROR; |
422 | 0 | } |
423 | 0 | Py_ssize_t utf8_len; |
424 | 0 | const char *utf8 = PyUnicode_AsUTF8AndSize(raw, &utf8_len); |
425 | 0 | if (utf8 == NULL) { |
426 | 0 | Py_DECREF(raw); |
427 | 0 | return _PYTOK_READ_ERROR; |
428 | 0 | } |
429 | 0 | input.owner = raw; |
430 | 0 | input.data = (char *)utf8; |
431 | 0 | input.len = utf8_len; |
432 | 0 | input.ownership = _PYTOK_CHUNK_PYOBJECT; |
433 | 0 | if (input.len == 0) { |
434 | 0 | _PyTok_ChunkClear(&input); |
435 | 0 | if (finalize_decoding(tok) < 0) { |
436 | 0 | return _PYTOK_READ_ERROR; |
437 | 0 | } |
438 | 0 | continue; |
439 | 0 | } |
440 | 0 | } |
441 | | |
442 | 0 | if (reader->decoded_pos == reader->decoded_len && |
443 | 0 | chunk_is_line(&input)) { |
444 | 0 | *chunk = input; |
445 | 0 | return _PYTOK_READ_LINE; |
446 | 0 | } |
447 | | |
448 | 0 | if (append_decoded(reader, input.data, input.len) < 0) { |
449 | 0 | _PyTok_ChunkClear(&input); |
450 | 0 | tok->done = E_NOMEM; |
451 | 0 | return _PYTOK_READ_ERROR; |
452 | 0 | } |
453 | 0 | _PyTok_ChunkClear(&input); |
454 | 0 | if (reader->decoded_pos < reader->decoded_len && |
455 | 0 | reader->decoded[reader->decoded_len - 1] != '\n') { |
456 | 0 | int pending = _PyTok_DecoderHasBufferedInput(tok); |
457 | 0 | if (pending < 0) { |
458 | 0 | return _PYTOK_READ_ERROR; |
459 | 0 | } |
460 | 0 | if (!pending && append_implicit_newline(reader) < 0) { |
461 | 0 | tok->done = E_NOMEM; |
462 | 0 | return _PYTOK_READ_ERROR; |
463 | 0 | } |
464 | 0 | } |
465 | 0 | if (pop_decoded_line(reader, chunk)) { |
466 | 0 | return _PYTOK_READ_LINE; |
467 | 0 | } |
468 | 0 | } |
469 | 0 | } |
470 | | |
471 | | static _PyTok_ReadResult |
472 | | next_interactive(struct tok_state *tok, _PyTok_Chunk *chunk) |
473 | 0 | { |
474 | 0 | _PyTok_Reader *reader = tok->reader; |
475 | 0 | if (tok->interactive_underflow == IUNDERFLOW_STOP) { |
476 | 0 | return _PYTOK_READ_STOPPED; |
477 | 0 | } |
478 | 0 | char *input = PyOS_Readline( |
479 | 0 | tok->fp != NULL ? tok->fp : stdin, stdout, tok->prompt); |
480 | 0 | if (reader->nextprompt != NULL) { |
481 | 0 | tok->prompt = reader->nextprompt; |
482 | 0 | } |
483 | 0 | if (input == NULL) { |
484 | 0 | return _PYTOK_READ_INTERRUPT; |
485 | 0 | } |
486 | 0 | Py_ssize_t len = strlen(input); |
487 | 0 | if (len == 0) { |
488 | 0 | PyMem_Free(input); |
489 | 0 | return _PYTOK_READ_EOF; |
490 | 0 | } |
491 | 0 | _PyTok_Chunk decoded = { |
492 | 0 | .data = input, |
493 | 0 | .len = len, |
494 | 0 | .ownership = _PYTOK_CHUNK_PYMEM, |
495 | 0 | }; |
496 | 0 | if (tok->encoding != NULL && |
497 | 0 | _PyTok_DecodeOnce( |
498 | 0 | tok, &decoded, tok->encoding, NULL) < 0) { |
499 | 0 | _PyTok_ChunkClear(&decoded); |
500 | 0 | return _PYTOK_READ_ERROR; |
501 | 0 | } |
502 | 0 | chunk->data = _PyTok_NormalizeNewlines( |
503 | 0 | decoded.data, decoded.len, 0, 0, |
504 | 0 | &chunk->len, &chunk->implicit_newline); |
505 | 0 | _PyTok_ChunkClear(&decoded); |
506 | 0 | if (chunk->data == NULL) { |
507 | 0 | PyErr_NoMemory(); |
508 | 0 | tok->done = E_NOMEM; |
509 | 0 | return _PYTOK_READ_ERROR; |
510 | 0 | } |
511 | 0 | chunk->ownership = _PYTOK_CHUNK_PYMEM; |
512 | 0 | return _PYTOK_READ_LINE; |
513 | 0 | } |
514 | | |
515 | | static _PyTok_ReadResult |
516 | | reader_next(struct tok_state *tok, _PyTok_Chunk *chunk) |
517 | 440k | { |
518 | 440k | *chunk = (_PyTok_Chunk){0}; |
519 | 440k | switch (tok->reader->kind) { |
520 | 440k | case _PYTOK_READER_PREPARED: |
521 | 440k | return next_prepared(tok, chunk); |
522 | 0 | case _PYTOK_READER_FILE: |
523 | 0 | return next_file(tok, chunk); |
524 | 0 | case _PYTOK_READER_READLINE: |
525 | 0 | return next_readline(tok, chunk); |
526 | 0 | case _PYTOK_READER_INTERACTIVE: |
527 | 0 | return next_interactive(tok, chunk); |
528 | 440k | } |
529 | 440k | Py_UNREACHABLE(); |
530 | 440k | } |
531 | | |
532 | | int |
533 | | _PyTok_ReaderUnderflow(struct tok_state *tok) |
534 | 440k | { |
535 | 440k | int prepared = tok->reader->kind == _PYTOK_READER_PREPARED; |
536 | 440k | int reset_buffer = !prepared && tok->start == NULL && !INSIDE_FSTRING(tok); |
537 | | |
538 | 440k | if (reset_buffer && tok->reader->kind != _PYTOK_READER_INTERACTIVE) { |
539 | 0 | tok->cur = tok->inp = tok->buf; |
540 | 0 | } |
541 | | |
542 | 440k | _PyTok_Chunk chunk; |
543 | 440k | _PyTok_ReadResult result = reader_next(tok, &chunk); |
544 | 440k | if (result != _PYTOK_READ_LINE) { |
545 | 19.4k | if (result == _PYTOK_READ_EOF) { |
546 | 19.4k | tok->done = E_EOF; |
547 | 19.4k | } |
548 | 0 | else if (result == _PYTOK_READ_STOPPED) { |
549 | 0 | tok->done = E_INTERACT_STOP; |
550 | 0 | } |
551 | 0 | else if (result == _PYTOK_READ_INTERRUPT) { |
552 | 0 | tok->done = E_INTR; |
553 | 0 | } |
554 | 0 | else { |
555 | 0 | tok->input_error = 1; |
556 | 0 | if (tok->done == E_OK) { |
557 | 0 | tok->done = PyErr_ExceptionMatches(PyExc_MemoryError) |
558 | 0 | ? E_NOMEM : E_ERROR; |
559 | 0 | } |
560 | 0 | } |
561 | 19.4k | if (tok->reader->kind == _PYTOK_READER_INTERACTIVE && |
562 | 0 | result != _PYTOK_READ_STOPPED) { |
563 | 0 | PySys_WriteStderr("\n"); |
564 | 0 | } |
565 | 19.4k | return 0; |
566 | 19.4k | } |
567 | | |
568 | 421k | Py_ssize_t copy_len = chunk.len; |
569 | 421k | if (tok->reader->kind == _PYTOK_READER_INTERACTIVE && |
570 | 0 | chunk.implicit_newline) { |
571 | 0 | copy_len--; |
572 | 0 | } |
573 | 421k | if (reset_buffer && tok->reader->kind == _PYTOK_READER_INTERACTIVE) { |
574 | 0 | tok->cur = tok->inp = tok->buf; |
575 | 0 | } |
576 | 421k | if (!prepared && !_PyLexer_tok_reserve_buf(tok, copy_len + 1)) { |
577 | 0 | _PyTok_ChunkClear(&chunk); |
578 | 0 | tok->input_error = 1; |
579 | 0 | return 0; |
580 | 0 | } |
581 | 421k | if (tok->reader->kind == _PYTOK_READER_INTERACTIVE && |
582 | 0 | _PyTok_SourceAppendLine(&tok->source, chunk.data, chunk.len, |
583 | 0 | chunk.implicit_newline) < 0) { |
584 | 0 | _PyTok_ChunkClear(&chunk); |
585 | 0 | tok->done = PyErr_ExceptionMatches(PyExc_MemoryError) |
586 | 0 | ? E_NOMEM : E_ERROR; |
587 | 0 | tok->input_error = 1; |
588 | 0 | return 0; |
589 | 0 | } |
590 | 421k | if (tok->fp_interactive) { |
591 | 0 | tok->interactive_src_start = tok->source.bytes; |
592 | 0 | tok->interactive_src_end = tok->source.bytes + tok->source.len; |
593 | 0 | } |
594 | 421k | if (prepared) { |
595 | 421k | if (tok->start == NULL) { |
596 | 355k | tok->buf = tok->cur; |
597 | 355k | } |
598 | 421k | tok->inp = chunk.data + chunk.len; |
599 | 421k | } |
600 | 0 | else { |
601 | 0 | memcpy(tok->inp, chunk.data, (size_t)copy_len); |
602 | 0 | tok->inp += copy_len; |
603 | 0 | *tok->inp = '\0'; |
604 | 0 | } |
605 | 421k | tok->implicit_newline = chunk.implicit_newline; |
606 | | |
607 | 421k | if (!prepared && tok->tok_mode_stack_index && |
608 | 0 | !_PyLexer_update_ftstring_expr(tok, 0)) { |
609 | 0 | _PyTok_ChunkClear(&chunk); |
610 | 0 | tok->input_error = 1; |
611 | 0 | return 0; |
612 | 0 | } |
613 | 421k | ADVANCE_LINENO(); |
614 | 421k | if (tok->reader->kind == _PYTOK_READER_FILE && |
615 | 0 | (tok->encoding == NULL || strcmp(tok->encoding, "utf-8") == 0) && |
616 | 0 | !_PyTokenizer_ensure_utf8(tok->cur, tok, tok->lineno)) { |
617 | 0 | _PyTok_ChunkClear(&chunk); |
618 | 0 | tok->input_error = 1; |
619 | 0 | return 0; |
620 | 0 | } |
621 | 421k | _PyTok_ChunkClear(&chunk); |
622 | 421k | return 1; |
623 | 421k | } |
624 | | |
625 | | static struct tok_state * |
626 | | tokenizer_new_with_reader(_PyTok_ReaderKind kind) |
627 | 24.5k | { |
628 | 24.5k | struct tok_state *tok = _PyTokenizer_tok_new(); |
629 | 24.5k | if (tok == NULL) { |
630 | 0 | return NULL; |
631 | 0 | } |
632 | 24.5k | tok->reader = PyMem_Calloc(1, sizeof(*tok->reader)); |
633 | 24.5k | if (tok->reader == NULL) { |
634 | 0 | PyErr_NoMemory(); |
635 | 0 | _PyTokenizer_Free(tok); |
636 | 0 | return NULL; |
637 | 0 | } |
638 | 24.5k | tok->reader->kind = kind; |
639 | 24.5k | if (kind == _PYTOK_READER_PREPARED) { |
640 | 24.5k | return tok; |
641 | 24.5k | } |
642 | 0 | tok->buf = PyMem_Malloc(BUFSIZ); |
643 | 0 | if (tok->buf == NULL) { |
644 | 0 | PyErr_NoMemory(); |
645 | 0 | _PyTokenizer_Free(tok); |
646 | 0 | return NULL; |
647 | 0 | } |
648 | 0 | tok->cur = tok->inp = tok->buf; |
649 | 0 | tok->end = tok->buf + BUFSIZ; |
650 | 0 | return tok; |
651 | 0 | } |
652 | | |
653 | | static struct tok_state * |
654 | | tokenizer_from_string(const char *input, int utf8_only, int exec_input, |
655 | | int preserve_crlf) |
656 | 24.5k | { |
657 | 24.5k | struct tok_state *tok = tokenizer_new_with_reader(_PYTOK_READER_PREPARED); |
658 | 24.5k | if (tok == NULL) { |
659 | 0 | return NULL; |
660 | 0 | } |
661 | 24.5k | if (_PyTok_PrepareString( |
662 | 24.5k | tok, input, utf8_only, exec_input, preserve_crlf) < 0) { |
663 | 1.90k | _PyTokenizer_Free(tok); |
664 | 1.90k | return NULL; |
665 | 1.90k | } |
666 | 22.6k | tok->buf = tok->cur = tok->inp = tok->str; |
667 | 22.6k | tok->end = tok->buf; |
668 | 22.6k | return tok; |
669 | 24.5k | } |
670 | | |
671 | | struct tok_state * |
672 | | _PyTokenizer_FromString(const char *input, int exec_input, int preserve_crlf) |
673 | 13.5k | { |
674 | 13.5k | return tokenizer_from_string(input, 0, exec_input, preserve_crlf); |
675 | 13.5k | } |
676 | | |
677 | | struct tok_state * |
678 | | _PyTokenizer_FromUTF8(const char *input, int exec_input, int preserve_crlf) |
679 | 11.0k | { |
680 | 11.0k | return tokenizer_from_string(input, 1, exec_input, preserve_crlf); |
681 | 11.0k | } |
682 | | |
683 | | struct tok_state * |
684 | | _PyTokenizer_FromReadline(PyObject *readline, const char *encoding) |
685 | 0 | { |
686 | 0 | struct tok_state *tok = tokenizer_new_with_reader(_PYTOK_READER_READLINE); |
687 | 0 | if (tok == NULL) { |
688 | 0 | return NULL; |
689 | 0 | } |
690 | 0 | if (encoding != NULL && _PyTok_SetEncoding(tok, encoding) < 0) { |
691 | 0 | _PyTokenizer_Free(tok); |
692 | 0 | return NULL; |
693 | 0 | } |
694 | 0 | tok->reader->readline = Py_NewRef(readline); |
695 | 0 | return tok; |
696 | 0 | } |
697 | | |
698 | | struct tok_state * |
699 | | _PyTokenizer_FromFile(FILE *fp, const char *encoding, |
700 | | const char *ps1, const char *ps2) |
701 | 0 | { |
702 | 0 | _PyTok_ReaderKind kind = ps1 != NULL || ps2 != NULL |
703 | 0 | ? _PYTOK_READER_INTERACTIVE : _PYTOK_READER_FILE; |
704 | 0 | struct tok_state *tok = tokenizer_new_with_reader(kind); |
705 | 0 | if (tok == NULL) { |
706 | 0 | return NULL; |
707 | 0 | } |
708 | 0 | if (encoding != NULL && _PyTok_SetEncoding(tok, encoding) < 0) { |
709 | 0 | _PyTokenizer_Free(tok); |
710 | 0 | return NULL; |
711 | 0 | } |
712 | 0 | tok->fp = fp; |
713 | 0 | tok->prompt = ps1; |
714 | 0 | tok->reader->nextprompt = ps2; |
715 | 0 | return tok; |
716 | 0 | } |
717 | | |
718 | | #if defined(__wasi__) || (defined(__EMSCRIPTEN__) && (__EMSCRIPTEN_major__ >= 3)) |
719 | | /* WASI has no dup(), and Emscripten's emulation is slow. */ |
720 | | typedef union { |
721 | | void *cookie; |
722 | | int fd; |
723 | | } borrowed_fd; |
724 | | |
725 | | static ssize_t |
726 | | borrow_read(void *cookie, char *buffer, size_t size) |
727 | | { |
728 | | borrowed_fd borrowed = {.cookie = cookie}; |
729 | | return read(borrowed.fd, buffer, size); |
730 | | } |
731 | | |
732 | | static FILE * |
733 | | fdopen_borrow(int fd) |
734 | | { |
735 | | cookie_io_functions_t callbacks = {borrow_read, NULL, NULL, NULL}; |
736 | | borrowed_fd borrowed = {.fd = fd}; |
737 | | return fopencookie(borrowed.cookie, "r", callbacks); |
738 | | } |
739 | | #else |
740 | | static FILE * |
741 | | fdopen_borrow(int fd) |
742 | 0 | { |
743 | 0 | int copy = _Py_dup(fd); |
744 | 0 | return copy < 0 ? NULL : fdopen(copy, "r"); |
745 | 0 | } |
746 | | #endif |
747 | | |
748 | | char * |
749 | | _PyTokenizer_FindEncodingFilename(int fd, PyObject *filename) |
750 | 0 | { |
751 | 0 | FILE *fp = fdopen_borrow(fd); |
752 | 0 | if (fp == NULL) { |
753 | 0 | return NULL; |
754 | 0 | } |
755 | 0 | struct tok_state *tok = _PyTokenizer_FromFile(fp, NULL, NULL, NULL); |
756 | 0 | if (tok == NULL) { |
757 | 0 | fclose(fp); |
758 | 0 | return NULL; |
759 | 0 | } |
760 | 0 | tok->filename = filename != NULL |
761 | 0 | ? Py_NewRef(filename) : PyUnicode_FromString("<string>"); |
762 | 0 | if (tok->filename == NULL) { |
763 | 0 | fclose(fp); |
764 | 0 | _PyTokenizer_Free(tok); |
765 | 0 | return NULL; |
766 | 0 | } |
767 | | /* Reporting a warning here could recursively ask for the encoding. */ |
768 | 0 | tok->report_warnings = 0; |
769 | 0 | while (tok->lineno < 2 && tok->done == E_OK) { |
770 | 0 | struct token token; |
771 | 0 | _PyToken_Init(&token); |
772 | 0 | _PyTokenizer_Get(tok, &token); |
773 | 0 | _PyToken_Free(&token); |
774 | 0 | } |
775 | 0 | fclose(fp); |
776 | 0 | char *encoding = tok->encoding == NULL |
777 | 0 | ? NULL : _PyTok_CopyBytes(tok->encoding, strlen(tok->encoding)); |
778 | 0 | _PyTokenizer_Free(tok); |
779 | 0 | return encoding; |
780 | 0 | } |