Bug 1869043 allow a device to be specified with MediaTrackGraph::NotifyWhenDeviceStar...
[gecko.git] / mozglue / interposers / getline_interposer.cpp
blob902b52b7187bb89051ac27cac92c1fcb15facba6
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/. */
5 /*
6 * Interposing getline because of
7 * https://bugzilla.mozilla.org/show_bug.cgi?id=914190
8 */
10 #ifdef __ANDROID__
12 # include <cstdlib>
13 # include <cstdio>
14 # include <cerrno>
16 # include <limits>
18 namespace {
20 // RAII on file locking.
21 class FileLocker {
22 FILE* stream;
24 public:
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) {
39 errno = EINVAL;
40 return -1;
43 // Lock the file so that we can us unlocked getc in the inner loop.
44 FileLocker fl(stream);
46 if (!*lineptr || *n == 0) {
47 *n = n_default;
48 if (auto* new_lineptr = reinterpret_cast<char*>(realloc(*lineptr, *n))) {
49 *lineptr = new_lineptr;
50 } else {
51 errno = ENOMEM;
52 return -1;
56 ssize_t result;
57 size_t cur_len = 0;
59 while (true) {
60 // Retrieve an extra char.
61 int i = getc_unlocked(stream);
62 if (i == EOF) {
63 result = -1;
64 break;
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) {
72 errno = EOVERFLOW;
73 return -1;
76 if (auto* new_lineptr = (char*)realloc(*lineptr, needed)) {
77 *lineptr = new_lineptr;
78 } else {
79 errno = ENOMEM;
80 return -1;
82 *n = needed;
85 (*lineptr)[cur_len] = i;
86 cur_len++;
88 if (i == delim) break;
90 (*lineptr)[cur_len] = '\0';
91 return cur_len ? cur_len : result;
94 } // namespace
96 extern "C" {
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);
108 } // extern "C"
110 #endif