#include #include #include #include #include #include #include #include /* ========================================================================= */ typedef struct jsoner_xtn_t jsoner_xtn_t; struct jsoner_xtn_t { int logfd; unsigned int logmask; int logfd_istty; struct { hcl_bch_t buf[4096]; hcl_oow_t len; } logbuf; }; /* ========================================================================= */ static void* sys_alloc (hcl_mmgr_t* mmgr, hcl_oow_t size) { return malloc(size); } static void* sys_realloc (hcl_mmgr_t* mmgr, void* ptr, hcl_oow_t size) { return realloc(ptr, size); } static void sys_free (hcl_mmgr_t* mmgr, void* ptr) { free (ptr); } static hcl_mmgr_t sys_mmgr = { sys_alloc, sys_realloc, sys_free, HCL_NULL }; /* ========================================================================= */ static int write_all (int fd, const hcl_bch_t* ptr, hcl_oow_t len) { while (len > 0) { hcl_ooi_t wr; wr = write(fd, ptr, len); if (wr <= -1) { #if defined(EAGAIN) && defined(EWOULDBLOCK) && (EAGAIN == EWOULDBLOCK) if (errno == EAGAIN) continue; #else #if defined(EAGAIN) if (errno == EAGAIN) continue; #elif defined(EWOULDBLOCK) if (errno == EWOULDBLOCK) continue; #endif #endif #if defined(EINTR) /* TODO: would this interfere with non-blocking nature of this VM? */ if (errno == EINTR) continue; #endif return -1; } ptr += wr; len -= wr; } return 0; } static int write_log (hcl_jsoner_t* jsoner, int fd, const hcl_bch_t* ptr, hcl_oow_t len) { jsoner_xtn_t* xtn; xtn = hcl_jsoner_getxtn(jsoner); while (len > 0) { if (xtn->logbuf.len > 0) { hcl_oow_t rcapa, cplen; rcapa = HCL_COUNTOF(xtn->logbuf.buf) - xtn->logbuf.len; cplen = (len >= rcapa)? rcapa: len; memcpy (&xtn->logbuf.buf[xtn->logbuf.len], ptr, cplen); xtn->logbuf.len += cplen; ptr += cplen; len -= cplen; if (xtn->logbuf.len >= HCL_COUNTOF(xtn->logbuf.buf)) { write_all(fd, xtn->logbuf.buf, xtn->logbuf.len); xtn->logbuf.len = 0; } } else { hcl_oow_t rcapa; rcapa = HCL_COUNTOF(xtn->logbuf.buf); if (len >= rcapa) { write_all (fd, ptr, rcapa); ptr += rcapa; len -= rcapa; } else { memcpy (xtn->logbuf.buf, ptr, len); xtn->logbuf.len += len; ptr += len; len -= len; } } } return 0; } static void flush_log (hcl_jsoner_t* jsoner, int fd) { jsoner_xtn_t* xtn; xtn = hcl_jsoner_getxtn(jsoner); if (xtn->logbuf.len > 0) { write_all (fd, xtn->logbuf.buf, xtn->logbuf.len); xtn->logbuf.len = 0; } } static void log_write (hcl_jsoner_t* jsoner, unsigned int mask, const hcl_ooch_t* msg, hcl_oow_t len) { hcl_bch_t buf[256]; hcl_oow_t ucslen, bcslen; jsoner_xtn_t* xtn; hcl_oow_t msgidx; int n, logfd; xtn = hcl_jsoner_getxtn(jsoner); if (mask & HCL_LOG_STDERR) { /* the messages that go to STDERR don't get masked out */ logfd = 2; } else { if (!(xtn->logmask & mask & ~HCL_LOG_ALL_LEVELS)) return; /* check log types */ if (!(xtn->logmask & mask & ~HCL_LOG_ALL_TYPES)) return; /* check log levels */ if (mask & HCL_LOG_STDOUT) logfd = 1; else { logfd = xtn->logfd; if (logfd <= -1) return; } } /* TODO: beautify the log message. * do classification based on mask. */ if (!(mask & (HCL_LOG_STDOUT | HCL_LOG_STDERR))) { time_t now; char ts[32]; size_t tslen; struct tm tm, *tmp; now = time(NULL); tmp = localtime_r (&now, &tm); #if defined(HAVE_STRFTIME_SMALL_Z) tslen = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S %z ", tmp); #else tslen = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S %Z ", tmp); #endif if (tslen == 0) { strcpy (ts, "0000-00-00 00:00:00 +0000"); tslen = 25; } write_log (jsoner, logfd, ts, tslen); } if (logfd == xtn->logfd && xtn->logfd_istty) { if (mask & HCL_LOG_FATAL) write_log (jsoner, logfd, "\x1B[1;31m", 7); else if (mask & HCL_LOG_ERROR) write_log (jsoner, logfd, "\x1B[1;32m", 7); else if (mask & HCL_LOG_WARN) write_log (jsoner, logfd, "\x1B[1;33m", 7); } #if defined(HCL_OOCH_IS_UCH) msgidx = 0; while (len > 0) { ucslen = len; bcslen = HCL_COUNTOF(buf); n = hcl_conv_oochars_to_bchars_with_cmgr(&msg[msgidx], &ucslen, buf, &bcslen, hcl_get_utf8_cmgr()); if (n == 0 || n == -2) { /* n = 0: * converted all successfully * n == -2: * buffer not sufficient. not all got converted yet. * write what have been converted this round. */ /*HCL_ASSERT (hcl, ucslen > 0); */ /* if this fails, the buffer size must be increased */ /*assert (ucslen > 0);*/ /* attempt to write all converted characters */ if (write_log(jsoner, logfd, buf, bcslen) <= -1) break; if (n == 0) break; else { msgidx += ucslen; len -= ucslen; } } else if (n <= -1) { /* conversion error */ break; } } #else write_log (jsoner, logfd, msg, len); #endif if (logfd == xtn->logfd && xtn->logfd_istty) { if (mask & (HCL_LOG_FATAL | HCL_LOG_ERROR | HCL_LOG_WARN)) write_log (jsoner, logfd, "\x1B[0m", 4); } flush_log (jsoner, logfd); } /* ========================================================================= */ int main (int argc, char* argv[]) { hcl_jsoner_t* jsoner; hcl_jsoner_prim_t json_prim; jsoner_xtn_t* jsoner_xtn; hcl_oow_t xlen; const char* p; memset (&json_prim, 0, HCL_SIZEOF(json_prim)); json_prim.log_write = log_write; jsoner = hcl_jsoner_open (&sys_mmgr, HCL_SIZEOF(jsoner_xtn_t), &json_prim, NULL); jsoner_xtn = hcl_jsoner_getxtn(jsoner); jsoner_xtn->logmask = HCL_LOG_ALL_LEVELS | HCL_LOG_ALL_TYPES; p = "[ \"ab\\xab\\uC88B\\uC544\\uC6A9c\", \"kaden\", \"iron\" ]"; hcl_jsoner_feed (jsoner, p, strlen(p), &xlen); hcl_jsoner_close (jsoner); return 0; }