diff options
Diffstat (limited to 'jni/compat/compat.c')
-rw-r--r-- | jni/compat/compat.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/jni/compat/compat.c b/jni/compat/compat.c new file mode 100644 index 0000000..c627f6a --- /dev/null +++ b/jni/compat/compat.c @@ -0,0 +1,58 @@ +#include "compat.h" +#include <unistd.h> +#include <pthread.h> +#include <android/log.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +int wctomb(char *s, wchar_t wc) { return wcrtomb(s,wc,NULL); } +int mbtowc(wchar_t *pwc, const char *s, size_t n) { return mbrtowc(pwc, s, n, NULL); } + +struct stream { + const char *name; + int fd[2]; + FILE *src; +}; + +static void* +log_thread(void *arg) +{ + struct stream *stream = arg; + char buf[4000], *off = buf, *nl; // Can't be too big or android stops logging + for (ssize_t r = 0;;off += r, r = 0) { + if (off - buf < sizeof(buf) - 1) { + errno = 0; + r = read(stream->fd[0], off, (sizeof(buf) - 1) - (off - buf)); + if (r <= 0) { if (errno == EINTR) continue; else break; } + off[r] = 0; + } + if ((nl = strrchr(off, '\n'))) { + *nl = 0; ++nl; + __android_log_write(ANDROID_LOG_INFO, stream->name, buf); + r = (off + r) - nl; + memcpy((off = buf), nl, r); + } else if (off - buf >= sizeof(buf)) { + __android_log_write(ANDROID_LOG_INFO, stream->name, buf); + r = 0; off = buf; + } + } + close(stream->fd[0]); + close(stream->fd[1]); + return NULL; +} + +__attribute__((constructor)) static void +log_init(void) { + static struct stream stream[] = { { .name = "stdout" }, { .name = "stderr" } }; + stream[0].src = stdout; stream[1].src = stderr; + for (size_t i = 0; i < sizeof(stream) / sizeof(stream[0]); ++i) { + setvbuf(stream[i].src, NULL, _IOLBF, BUFSIZ); + pipe(stream[i].fd); + dup2(stream[i].fd[1], fileno(stream[i].src)); + pthread_t thread; + pthread_create(&thread, 0, log_thread, &stream[i]); + pthread_detach(thread); + } + chdir(getenv("COMPAT_CHDIR")); +} |