summaryrefslogtreecommitdiff
path: root/jni/compat/compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'jni/compat/compat.c')
-rw-r--r--jni/compat/compat.c58
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"));
+}