summaryrefslogtreecommitdiff
path: root/src/libc-stdio.c
blob: 0d19f205e5568ce79c2d3573a96e6e3c0f006804 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <stdio.h>

struct bionic___sFILE {
#if defined(__LP64__)
   char __private[152];
#else
   char __private[84];
#endif
} __attribute__((aligned(sizeof(void*))));

// Bionic standard stream support pre-M Android
// Post-M it's saner and they point to stdin/stdout/stderr symbols instead
const struct bionic___sFILE bionic___sF[3] = {
   {{ 's''t''d''i''n' }},
   {{ 's''t''d''o''u''t' }},
   {{ 's''t''d''e''r''r' }}
};

static inline FILE*
bionic_file_to_glibc_file(FILE *f)
{
   if (f == (void*)&bionic___sF[0])
      return stdin;
   else if (f == (void*)&bionic___sF[1])
      return stdout;
   else if (f == (void*)&bionic___sF[2])
      return stderr;
   return f;
}

// libstdc++ uses these directly for standard streams, thus we need to wrap em
// and IO_file wraps aren't enough.

int
bionic_fflush(FILE *f)
{
   return fflush(bionic_file_to_glibc_file(f));
}

size_t
bionic_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
{
   return fwrite(ptr, size, nmemb, bionic_file_to_glibc_file(stream));
}

int
bionic_putc(int ch, FILE *f)
{
   return putc(ch, bionic_file_to_glibc_file(f));
}

// Wrapping internal glibc VTABLE functions to handle bionic's pre-M crap
// We define __real_IO_file_xsputn in libc.c so linker will link our library,
// it's not used however for anything.

extern size_t
__real_IO_file_xsputn(FILE *f, const void *buf, size_t n);

size_t
__wrap_IO_file_xsputn(FILE *f, const void *buf, size_t n)
{
   return __real_IO_file_xsputn(bionic_file_to_glibc_file(f), buf, n);
}