summaryrefslogtreecommitdiff
path: root/jni/compat/compat.c
blob: c627f6ae6982733c41a04bc589e0860856a65f45 (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
#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 == EINTRcontinueelse 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_IOLBFBUFSIZ);
      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"));
}