Coverage Report

Created: 2026-09-01 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}