1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 * Interposing getline because of
7 * https://bugzilla.mozilla.org/show_bug.cgi?id=914190
20 // RAII on file locking.
25 explicit FileLocker(FILE* stream
) : stream(stream
) { flockfile(stream
); }
26 ~FileLocker() { funlockfile(stream
); }
29 ssize_t
internal_getdelim(char** __restrict lineptr
, size_t* __restrict n
,
30 int delim
, FILE* __restrict stream
) {
31 constexpr size_t n_default
= 64;
32 constexpr size_t n_max
=
33 std::numeric_limits
<ssize_t
>::max() < std::numeric_limits
<size_t>::max()
34 ? (size_t)std::numeric_limits
<ssize_t
>::max() + 1
35 : std::numeric_limits
<size_t>::max();
36 constexpr size_t n_limit
= 2 * ((n_max
- 1) / 3);
38 if (!lineptr
|| !n
|| !stream
) {
43 // Lock the file so that we can us unlocked getc in the inner loop.
44 FileLocker
fl(stream
);
46 if (!*lineptr
|| *n
== 0) {
48 if (auto* new_lineptr
= reinterpret_cast<char*>(realloc(*lineptr
, *n
))) {
49 *lineptr
= new_lineptr
;
60 // Retrieve an extra char.
61 int i
= getc_unlocked(stream
);
67 // Eventually grow the buffer.
68 if (cur_len
+ 1 >= *n
) {
69 size_t needed
= *n
>= n_limit
? n_max
: 3 * *n
/ 2 + 1;
71 if (cur_len
+ 1 >= needed
) {
76 if (auto* new_lineptr
= (char*)realloc(*lineptr
, needed
)) {
77 *lineptr
= new_lineptr
;
85 (*lineptr
)[cur_len
] = i
;
88 if (i
== delim
) break;
90 (*lineptr
)[cur_len
] = '\0';
91 return cur_len
? cur_len
: result
;
98 MFBT_API ssize_t
getline(char** __restrict lineptr
, size_t* __restrict n
,
99 FILE* __restrict stream
) {
100 return internal_getdelim(lineptr
, n
, '\n', stream
);
103 MFBT_API ssize_t
getdelim(char** __restrict lineptr
, size_t* __restrict n
,
104 int delim
, FILE* __restrict stream
) {
105 return internal_getdelim(lineptr
, n
, delim
, stream
);