From 93cc3d6da4074c8a1f4476123282ae0e077bb72c Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Thu, 14 Sep 2017 18:19:51 +0000 Subject: [PATCH] added some logging functions --- qse/configure | 13 +- qse/configure.ac | 3 +- qse/include/qse/cmn/time.h | 2 +- qse/include/qse/config.h.in | 6 + qse/include/qse/si/Makefile.am | 1 + qse/include/qse/si/Makefile.in | 10 +- qse/include/qse/si/log.h | 320 +++++++++++++++++++ qse/lib/cmn/Makefile.am | 3 +- qse/lib/cmn/Makefile.in | 3 +- qse/lib/cmn/String.cpp | 21 +- qse/lib/cmn/str-dyn.c | 21 +- qse/lib/cmn/time.c | 70 ++++- qse/lib/cmn/va_copy.h | 53 ++++ qse/lib/si/Makefile.am | 1 + qse/lib/si/Makefile.in | 20 +- qse/lib/si/log.c | 560 +++++++++++++++++++++++++++++++++ 16 files changed, 1047 insertions(+), 60 deletions(-) create mode 100644 qse/include/qse/si/log.h create mode 100644 qse/lib/cmn/va_copy.h create mode 100644 qse/lib/si/log.c diff --git a/qse/configure b/qse/configure index a8bef749..95797f79 100755 --- a/qse/configure +++ b/qse/configure @@ -19353,7 +19353,7 @@ _ACEOF fi done -for ac_func in timegm timelocal localtime_r gettimeofday settimeofday +for ac_func in timegm timelocal localtime_r gmtime_r gettimeofday settimeofday do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -20895,6 +20895,17 @@ cat >>confdefs.h <<_ACEOF _ACEOF +fi + +ac_fn_c_check_member "$LINENO" "struct tm" "tm_gmtoff" "ac_cv_member_struct_tm_tm_gmtoff" "#include +" +if test "x$ac_cv_member_struct_tm_tm_gmtoff" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_TM_TM_GMTOFF 1 +_ACEOF + + fi diff --git a/qse/configure.ac b/qse/configure.ac index f678eb78..315d332f 100644 --- a/qse/configure.ac +++ b/qse/configure.ac @@ -149,7 +149,7 @@ AC_CHECK_FUNCS([lseek64 ftruncate64 readdir64 dirfd]) AC_CHECK_FUNCS([stat64 fstat64 lstat64 fstatat64]) AC_CHECK_FUNCS([fstat fstatat]) AC_CHECK_FUNCS([fchmod fchmodat fchown fchownat fsync ftruncate]) -AC_CHECK_FUNCS([timegm timelocal localtime_r gettimeofday settimeofday]) +AC_CHECK_FUNCS([timegm timelocal localtime_r gmtime_r gettimeofday settimeofday]) AC_CHECK_FUNCS([utime utimes futimes lutimes futimens utimensat]) AC_CHECK_FUNCS([sysconf prctl fdopendir setrlimit getrlimit getpgid getpgrp]) AC_CHECK_FUNCS([backtrace backtrace_symbols]) @@ -321,6 +321,7 @@ AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec]) AC_CHECK_MEMBERS([struct stat.st_birthtim.tv_nsec]) AC_CHECK_MEMBERS([struct stat.st_mtimespec.tv_nsec]) AC_CHECK_MEMBERS([struct stat.st_birthtimespec.tv_nsec]) +AC_CHECK_MEMBERS([struct tm.tm_gmtoff],,,[[#include ]]) AC_CHECK_MEMBERS([struct ifreq.ifr_ifindex, struct ifreq.ifr_mtu], [], [], diff --git a/qse/include/qse/cmn/time.h b/qse/include/qse/cmn/time.h index 889f1754..c35bd9fb 100644 --- a/qse/include/qse/cmn/time.h +++ b/qse/include/qse/cmn/time.h @@ -116,7 +116,7 @@ struct qse_btime_t int wday; /* 0(sun)-6(sat) */ int yday; /* 0(jan 1) to 365 */ int isdst; /* -1(unknown), 0(not in effect), 1 (in effect) */ - /*int offset;*/ + int gmtoff; }; #define qse_inittime(x,s,ns) (((x)->sec = (s)), ((x)->nsec = (ns))) diff --git a/qse/include/qse/config.h.in b/qse/include/qse/config.h.in index fc69a7e5..ffcd5638 100644 --- a/qse/include/qse/config.h.in +++ b/qse/include/qse/config.h.in @@ -296,6 +296,9 @@ /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY +/* Define to 1 if you have the `gmtime_r' function. */ +#undef HAVE_GMTIME_R + /* Define to 1 if you have the header file. */ #undef HAVE_IFADDRS_H @@ -641,6 +644,9 @@ /* Define to 1 if the system has the type `struct timespec'. */ #undef HAVE_STRUCT_TIMESPEC +/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */ +#undef HAVE_STRUCT_TM_TM_GMTOFF + /* Define to 1 if you have the `swapcontext' function. */ #undef HAVE_SWAPCONTEXT diff --git a/qse/include/qse/si/Makefile.am b/qse/include/qse/si/Makefile.am index d7b27ceb..88880987 100644 --- a/qse/include/qse/si/Makefile.am +++ b/qse/include/qse/si/Makefile.am @@ -10,6 +10,7 @@ pkginclude_HEADERS = \ fs.h \ glob.h \ intr.h \ + log.h \ mtx.h \ mux.h \ nwad.h \ diff --git a/qse/include/qse/si/Makefile.in b/qse/include/qse/si/Makefile.in index cb07688f..f724456d 100644 --- a/qse/include/qse/si/Makefile.in +++ b/qse/include/qse/si/Makefile.in @@ -129,9 +129,9 @@ am__can_run_installinfo = \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__pkginclude_HEADERS_DIST = aio.h aio-pro.h aio-sck.h cnd.h dir.h \ - fio.h fs.h glob.h intr.h mtx.h mux.h nwad.h nwif.h nwio.h \ - pio.h rwl.h sck.h sio.h task.h thr.h tio.h SocketAddress.hpp \ - Socket.hpp + fio.h fs.h glob.h intr.h log.h mtx.h mux.h nwad.h nwif.h \ + nwio.h pio.h rwl.h sck.h sio.h task.h thr.h tio.h \ + SocketAddress.hpp Socket.hpp am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ @@ -365,8 +365,8 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ pkginclude_HEADERS = aio.h aio-pro.h aio-sck.h cnd.h dir.h fio.h fs.h \ - glob.h intr.h mtx.h mux.h nwad.h nwif.h nwio.h pio.h rwl.h \ - sck.h sio.h task.h thr.h tio.h $(am__append_1) + glob.h intr.h log.h mtx.h mux.h nwad.h nwif.h nwio.h pio.h \ + rwl.h sck.h sio.h task.h thr.h tio.h $(am__append_1) all: all-am .SUFFIXES: diff --git a/qse/include/qse/si/log.h b/qse/include/qse/si/log.h new file mode 100644 index 00000000..825a7629 --- /dev/null +++ b/qse/include/qse/si/log.h @@ -0,0 +1,320 @@ +/* + * $Id$ + * + Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _QSE_SI_LOG_H_ +#define _QSE_SI_LOG_H_ + +#include +#include +#include +#include +#include +#include + +/* TODO: improve this and complete win32 portion */ + +#define QSE_LOG_MSG_MAX 10204 +#define QSE_LOG_IDENT_MAX 32 + +/* priority */ +#define QSE_LOG_PANIC (1UL << 0) +#define QSE_LOG_ALERT (1UL << 1) +#define QSE_LOG_CRITICAL (1UL << 2) +#define QSE_LOG_ERROR (1UL << 3) +#define QSE_LOG_WARNING (1UL << 4) +#define QSE_LOG_NOTICE (1UL << 5) +#define QSE_LOG_INFO (1UL << 6) +#define QSE_LOG_DEBUG (1UL << 7) + +/* options */ +#define QSE_LOG_KEEP_FILE_OPEN (1UL << 13) +#define QSE_LOG_ENABLE_MASKED (1UL << 14) +#define QSE_LOG_SYSLOG_PID (1UL << 15) + +/* target */ +#define QSE_LOG_CONSOLE (1UL << 20) +#define QSE_LOG_FILE (1UL << 21) +#define QSE_LOG_SYSLOG (1UL << 22) +#define QSE_LOG_SYSLOG_REMOTE (1UL << 23) + +#define QSE_LOG_MASK_PRIORITY 0x00000FFFUL +#define QSE_LOG_MASK_OPTION 0x000FF000UL +#define QSE_LOG_MASK_TARGET 0xFFF00000UL + + +/* facility */ +enum qse_log_facility_t +{ + QSE_LOG_KERN = (0<<3), /* kernel messages */ + QSE_LOG_USER = (1<<3), /* random user-level messages */ + QSE_LOG_MAIL = (2<<3), /* mail system */ + QSE_LOG_DAEMON = (3<<3), /* system daemons */ + QSE_LOG_AUTH = (4<<3), /* security/authorization messages */ + QSE_LOG_SYSLOGD = (5<<3), /* messages from syslogd */ + QSE_LOG_LPR = (6<<3), /* line printer subsystem */ + QSE_LOG_NEWS = (7<<3), /* network news subsystem */ + QSE_LOG_UUCP = (8<<3), /* UUCP subsystem */ + QSE_LOG_CRON = (9<<3), /* clock daemon */ + QSE_LOG_AUTHPRIV = (10<<3), /* authorization messages (private) */ + QSE_LOG_FTP = (11<<3), /* ftp daemon */ + QSE_LOG_LOCAL0 = (16<<3), /* reserved for local use */ + QSE_LOG_LOCAL1 = (17<<3), /* reserved for local use */ + QSE_LOG_LOCAL2 = (18<<3), /* reserved for local use */ + QSE_LOG_LOCAL3 = (19<<3), /* reserved for local use */ + QSE_LOG_LOCAL4 = (20<<3), /* reserved for local use */ + QSE_LOG_LOCAL5 = (21<<3), /* reserved for local use */ + QSE_LOG_LOCAL6 = (22<<3), /* reserved for local use */ + QSE_LOG_LOCAL7 = (23<<3) /* reserved for local use */ +}; +typedef enum qse_log_facility_t qse_log_facility_t; + + +#define QSE_LOG_ENABLED(log,pri) ((pri) <= ((log)->flags & QSE_LOG_MASK_PRIORITY)) + +#define QSE_LOG0(log,ident,pri,fmt) \ + do { \ + if (QSE_LOG_ENABLED(log,pri)) \ + qse_log_report (log, ident, pri, fmt); \ + } while (0) + +#define QSE_LOG1(log,ident,pri,fmt,m1) \ + do { \ + if (QSE_LOG_ENABLED(log,pri)) \ + qse_log_report (log, ident, pri, fmt, m1); \ + } while (0) +#define QSE_LOG2(log,ident,pri,fmt,m1,m2) \ + do { \ + if (QSE_LOG_ENABLED(log,pri)) \ + qse_log_report (log, ident, pri, fmt, m1, m2); \ + } while (0) +#define QSE_LOG3(log,ident,pri,fmt,m1,m2,m3) \ + do { \ + if (QSE_LOG_ENABLED(log,pri)) \ + qse_log_report (log, ident, pri, fmt, m1, m2, m3); \ + } while (0) +#define QSE_LOG4(log,ident,pri,fmt,m1,m2,m3,m4) \ + do { \ + if (QSE_LOG_ENABLED(log,pri)) \ + qse_log_report (log, ident, pri, fmt, m1, m2, m3, m4); \ + } while (0) +#define QSE_LOG5(log,ident,pri,fmt,m1,m2,m3,m4,m5) \ + do { \ + if (QSE_LOG_ENABLED(log,pri)) \ + qse_log_report (log, ident, pri, fmt, m1, m2, m3, m4, m5); \ + } while (0) + +#define QSE_LOG6(log,ident,pri,fmt,m1,m2,m3,m4,m5,m6) \ + do { \ + if (QSE_LOG_ENABLED(log,pri)) \ + qse_log_report (log, ident, pri, fmt, m1, m2, m3, m4, m5, m6); \ + } while (0) + +#define QSE_LOG7(log,ident,pri,fmt,m1,m2,m3,m4,m5,m6,m7) \ + do { \ + if (QSE_LOG_ENABLED(log,pri)) \ + qse_log_report (log, ident, pri, fmt, m1, m2, m3, m4, m5, m6, m7); \ + } while (0) + +#define QSE_LOG8(log,ident,pri,fmt,m1,m2,m3,m4,m5,m6,m7,m8) \ + do { \ + if (QSE_LOG_ENABLED(log,pri)) \ + qse_log_report (log, ident, pri, fmt, m1, m2, m3, m4, m5, m6, m7, m8); \ + } while (0) + +#define QSE_LOG9(log,ident,pri,fmt,m1,m2,m3,m4,m5,m6,m7,m8,m9) \ + do { \ + if (QSE_LOG_ENABLED(log,pri)) \ + qse_log_report (log, ident, pri, fmt, m1, m2, m3, m4, m5, m6, m7, m8, m9); \ + } while (0) + +#define QSE_LOG10(log,ident,pri,fmt,m1,m2,m3,m4,m5,m6,m7,m8,m9,m10) \ + do { \ + if (QSE_LOG_ENABLED(log,pri)) \ + qse_log_report (log, ident, pri, fmt, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10); \ + } while (0) + +#define QSE_LOG11(log,ident,pri,fmt,m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11) \ + do { \ + if (QSE_LOG_ENABLED(log,pri)) \ + qse_log_report (log, ident, pri, fmt, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11); \ + } while (0) + +#define QSE_LOG12(log,ident,pri,fmt,m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11,m12) \ + do { \ + if (QSE_LOG_ENABLED(log,pri)) \ + qse_log_report (log, ident, pri, fmt, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11 ,m12); \ + } while (0) +#define QSE_LOG13(log,ident,pri,fmt,m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11,m12,m13) \ + do { \ + if (QSE_LOG_ENABLED(log,pri)) \ + qse_log_report (log, ident, pri, fmt, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13); \ + } while (0) +#define QSE_LOG14(log,ident,pri,fmt,m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11,m12,m13,m14) \ + do { \ + if (QSE_LOG_ENABLED(log,pri)) \ + qse_log_report (log, ident, pri, fmt, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14); \ + } while (0) +#define QSE_LOG15(log,ident,pri,fmt,m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11,m12,m13,m14,m15) \ + do { \ + if (QSE_LOG_ENABLED(log,pri)) \ + qse_log_report (log, ident, pri, fmt, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15); \ + } while (0) + + +typedef struct qse_log_t qse_log_t; +struct qse_log_t +{ + qse_mmgr_t* mmgr; + int flags; + + struct + { + struct + { + qse_sio_t* sio; + } console; + + struct + { + qse_char_t path[/*QSE_PATH_MAX + 1*/2048]; /* TODO: use the defined macro for sizing */ + qse_sio_t* sio; + } file; + + struct + { + int opened; + } syslog; + + struct + { + qse_skad_t addr; + int sock; + } syslog_remote; + } t; + + qse_char_t ident[QSE_LOG_IDENT_MAX + 1]; + qse_mbs_t* dmsgbuf; + qse_mtx_t mtx; + +#if !defined(_WIN32) + qse_log_facility_t syslog_facility; +#endif +}; + + +struct qse_log_target_t +{ + const qse_char_t* file; + qse_skad_t syslog_remote; +}; +typedef struct qse_log_target_t qse_log_target_t; + +#ifdef __cplusplus +extern "C" { +#endif + +qse_log_t* qse_log_open ( + qse_mmgr_t* mmgr, + qse_size_t xtnsize, + const qse_char_t* ident, + int potflags, /* priority + option + target bits */ + const qse_log_target_t* target +); + +void qse_log_close ( + qse_log_t* log +); + +void qse_log_setident ( + qse_log_t* log, + const qse_char_t* ident +); + +void qse_log_settarget ( + qse_log_t* log, + int flags, + const qse_log_target_t* target +); + +int qse_log_gettarget ( + qse_log_t* log, + qse_log_target_t* target +); + +void qse_log_setpriority ( + qse_log_t* log, + int priority +); + +int qse_log_setprioritybyname ( + qse_log_t* log, + const qse_char_t* name +); + +void qse_log_setsyslogfacility ( + qse_log_t* log, + qse_log_facility_t facility +); + +int qse_log_setsyslogfacilitybyname ( + qse_log_t* log, + const qse_char_t* name +); + +int qse_log_getpriority ( + qse_log_t* log +); + +const qse_char_t* qse_log_getpriorityname ( + qse_log_t* log +); + + +void qse_log_report ( + qse_log_t* log, + const qse_char_t* ident, + int pri, + const qse_char_t* fmt, + ... +); + +void qse_log_reportv ( + qse_log_t* log, + const qse_char_t* ident, + int pri, + const qse_char_t* fmt, + va_list ap +); + +const qse_char_t* qse_get_log_priority_name ( + int pri +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/qse/lib/cmn/Makefile.am b/qse/lib/cmn/Makefile.am index 34cffc6c..3f37728f 100644 --- a/qse/lib/cmn/Makefile.am +++ b/qse/lib/cmn/Makefile.am @@ -28,7 +28,8 @@ noinst_HEADERS = \ tre-parse.h \ tre-stack.h \ uni-case.h \ - uni-trait.h + uni-trait.h \ + va_copy.h libqsecmn_la_SOURCES = \ alg-base64.c \ diff --git a/qse/lib/cmn/Makefile.in b/qse/lib/cmn/Makefile.in index 56d7e4d5..e8342e6a 100644 --- a/qse/lib/cmn/Makefile.in +++ b/qse/lib/cmn/Makefile.in @@ -482,7 +482,8 @@ noinst_HEADERS = \ tre-parse.h \ tre-stack.h \ uni-case.h \ - uni-trait.h + uni-trait.h \ + va_copy.h libqsecmn_la_SOURCES = alg-base64.c alg-rand.c alg-search.c alg-sort.c \ arr.c assert.c chr.c dll.c env.c gdl.c htb.c fma.c \ diff --git a/qse/lib/cmn/String.cpp b/qse/lib/cmn/String.cpp index 08f2c24c..dc350e4c 100644 --- a/qse/lib/cmn/String.cpp +++ b/qse/lib/cmn/String.cpp @@ -26,26 +26,7 @@ #include #include "mem-prv.h" - -#if !defined(QSE_HAVE_CONFIG_H) -# if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) -# if (defined(__WATCOMC__) && (__WATCOMC__ < 1200)) || defined(__BORLANDC__) -# undef HAVE_VA_COPY -# undef HAVE___VA_COPY -# else -# define HAVE_VA_COPY -# define HAVE___VA_COPY -# endif -# endif -#endif - -#if !defined(HAVE_VA_COPY) -# if defined(HAVE___VA_COPY) -# define va_copy(dst,src) __va_copy((dst),(src)) -# else -# define va_copy(dst,src) QSE_MEMCPY(&(dst),&(src),QSE_SIZEOF(va_list)) -# endif -#endif +#include "va_copy.h" ///////////////////////////////// QSE_BEGIN_NAMESPACE(QSE) diff --git a/qse/lib/cmn/str-dyn.c b/qse/lib/cmn/str-dyn.c index 51c862e5..dd48c918 100644 --- a/qse/lib/cmn/str-dyn.c +++ b/qse/lib/cmn/str-dyn.c @@ -27,26 +27,7 @@ #include #include #include "mem-prv.h" - -#if !defined(QSE_HAVE_CONFIG_H) -# if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) -# if (defined(__WATCOMC__) && (__WATCOMC__ < 1200)) || defined(__BORLANDC__) -# undef HAVE_VA_COPY -# undef HAVE___VA_COPY -# else -# define HAVE_VA_COPY -# define HAVE___VA_COPY -# endif -# endif -#endif - -#if !defined(HAVE_VA_COPY) -# if defined(HAVE___VA_COPY) -# define va_copy(dst,src) __va_copy((dst),(src)) -# else -# define va_copy(dst,src) QSE_MEMCPY(&(dst),&(src),QSE_SIZEOF(va_list)) -# endif -#endif +#include "va_copy.h" static int put_mchar_null (qse_mchar_t c, void* ctx) { diff --git a/qse/lib/cmn/time.c b/qse/lib/cmn/time.c index 1162fa1d..98a26f35 100644 --- a/qse/lib/cmn/time.c +++ b/qse/lib/cmn/time.c @@ -271,14 +271,14 @@ int qse_settime (const qse_ntime_t* t) #endif } -static void breakdown_time (const qse_ntime_t* nt, qse_btime_t* bt, qse_long_t offset) +static void breakdown_time (const qse_ntime_t* nt, qse_btime_t* bt, qse_long_t gmtoff) { int midx; qse_long_t days; /* total days */ qse_long_t secs; /* the remaining seconds */ qse_long_t year = QSE_EPOCH_YEAR; - secs = nt->sec + offset; /* offset in seconds */ + secs = nt->sec + gmtoff; /* offset in seconds */ days = secs / QSE_SECS_PER_DAY; secs %= QSE_SECS_PER_DAY; @@ -331,13 +331,63 @@ static void breakdown_time (const qse_ntime_t* nt, qse_btime_t* bt, qse_long_t o bt->mday = days + 1; bt->isdst = 0; /* TODO: this may vary depeding on offset and time */ - /*bt->offset = offset;*/ + bt->gmtoff = gmtoff; } int qse_gmtime (const qse_ntime_t* nt, qse_btime_t* bt) { +#if 0 breakdown_time (nt, bt, 0); return 0; +#else + + struct tm* tm; + time_t t = nt->sec; + + /* TODO: remove dependency on gmtime/gmtime_r */ +#if defined(_WIN32) + tm = gmtime (&t); +#elif defined(__OS2__) +# if defined(__WATCOMC__) + struct tm btm; + tm = _gmtime (&t, &btm); +# else +# error Please support other compilers +# endif +#elif defined(__DOS__) +# if defined(__WATCOMC__) + struct tm btm; + tm = _gmtime (&t, &btm); +# else +# error Please support other compilers +# endif +#elif defined(HAVE_GMTIME_R) + struct tm btm; + tm = gmtime_r (&t, &btm); +#else + /* thread unsafe */ + tm = gmtime_r (&t); +#endif + if (tm == QSE_NULL) return -1; + + QSE_MEMSET (bt, 0, QSE_SIZEOF(*bt)); + + bt->sec = tm->tm_sec; + bt->min = tm->tm_min; + bt->hour = tm->tm_hour; + bt->mday = tm->tm_mday; + bt->mon = tm->tm_mon; + bt->year = tm->tm_year; + bt->wday = tm->tm_wday; + bt->yday = tm->tm_yday; + bt->isdst = tm->tm_isdst; +#if defined(HAVE_STRUCT_TM_TM_GMTOFF) + bt->gmtoff = tm->tm_gmtoff; +#endif + + return 0; + +#endif } int qse_localtime (const qse_ntime_t* nt, qse_btime_t* bt) @@ -370,7 +420,7 @@ int qse_localtime (const qse_ntime_t* nt, qse_btime_t* bt) tm = localtime (&t); #endif if (tm == QSE_NULL) return -1; - + QSE_MEMSET (bt, 0, QSE_SIZEOF(*bt)); bt->sec = tm->tm_sec; @@ -382,7 +432,11 @@ int qse_localtime (const qse_ntime_t* nt, qse_btime_t* bt) bt->wday = tm->tm_wday; bt->yday = tm->tm_yday; bt->isdst = tm->tm_isdst; - /*bt->offset = tm->tm_offset;*/ +#if defined(HAVE_STRUCT_TM_TM_GMTOFF) + bt->gmtoff = tm->tm_gmtoff; +#else + bt->gmtoff = QSE_TYPE_MIN(int); /* unknown */ +#endif return 0; } @@ -427,6 +481,9 @@ int qse_timegm (const qse_btime_t* bt, qse_ntime_t* nt) tm.tm_wday = bt->wday; tm.tm_yday = bt->yday; tm.tm_isdst = bt->isdst; +#if defined(HAVE_STRUCT_TM_TM_GMTOFF) + tm->tm_gmtoff = bt->gmtoff; /* i don't think this is needed. but just keep it */ +#endif #if defined(HAVE_TIMEGM) *nt = ((qse_ntime_t)timegm(&tm)*QSE_MSECS_PER_SEC) + bt->msec; @@ -513,6 +570,9 @@ int qse_timelocal (const qse_btime_t* bt, qse_ntime_t* nt) tm.tm_wday = bt->wday; tm.tm_yday = bt->yday; tm.tm_isdst = bt->isdst; +#if defined(HAVE_STRUCT_TM_TM_GMTOFF) + tm.tm_gmtoff = bt->gmtoff; /* i don't think this is needed. but just keep it */ +#endif #if defined(HAVE_TIMELOCAL) nt->sec = timelocal (&tm); diff --git a/qse/lib/cmn/va_copy.h b/qse/lib/cmn/va_copy.h new file mode 100644 index 00000000..207f6a53 --- /dev/null +++ b/qse/lib/cmn/va_copy.h @@ -0,0 +1,53 @@ +/* + * $Id$ + * + Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _QSE_LIB_CMN_VA_COPY_H_ +#define _QSE_LIB_CMN_VA_COPY_H_ + +#include +#include + +#if !defined(QSE_HAVE_CONFIG_H) +# if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) +# if (defined(__WATCOMC__) && (__WATCOMC__ < 1200)) || defined(__BORLANDC__) +# undef HAVE_VA_COPY +# undef HAVE___VA_COPY +# else +# define HAVE_VA_COPY +# define HAVE___VA_COPY +# endif +# endif +#endif + +#if !defined(HAVE_VA_COPY) +# if defined(HAVE___VA_COPY) +# define va_copy(dst,src) __va_copy((dst),(src)) +# else +# define va_copy(dst,src) QSE_MEMCPY(&(dst),&(src),QSE_SIZEOF(va_list)) +# endif +#endif + +#endif diff --git a/qse/lib/si/Makefile.am b/qse/lib/si/Makefile.am index 2eaa6a20..3288d83a 100644 --- a/qse/lib/si/Makefile.am +++ b/qse/lib/si/Makefile.am @@ -27,6 +27,7 @@ libqsesi_la_SOURCES = \ fs-move.c \ glob.c \ intr.c \ + log.c \ mtx.c \ mux.c \ nwad.c \ diff --git a/qse/lib/si/Makefile.in b/qse/lib/si/Makefile.in index 3c8bea90..4d7684f2 100644 --- a/qse/lib/si/Makefile.in +++ b/qse/lib/si/Makefile.in @@ -146,11 +146,12 @@ am_libqsesi_la_OBJECTS = libqsesi_la-aio.lo libqsesi_la-aio-pro.lo \ libqsesi_la-fs-copy.lo libqsesi_la-fs-delete.lo \ libqsesi_la-fs-err.lo libqsesi_la-fs-make.lo \ libqsesi_la-fs-move.lo libqsesi_la-glob.lo libqsesi_la-intr.lo \ - libqsesi_la-mtx.lo libqsesi_la-mux.lo libqsesi_la-nwad.lo \ - libqsesi_la-nwad-skad.lo libqsesi_la-nwif.lo \ - libqsesi_la-nwif-cfg.lo libqsesi_la-nwio.lo libqsesi_la-pio.lo \ - libqsesi_la-rwl.lo libqsesi_la-sck.lo libqsesi_la-sio.lo \ - libqsesi_la-task.lo libqsesi_la-thr.lo libqsesi_la-tio.lo + libqsesi_la-log.lo libqsesi_la-mtx.lo libqsesi_la-mux.lo \ + libqsesi_la-nwad.lo libqsesi_la-nwad-skad.lo \ + libqsesi_la-nwif.lo libqsesi_la-nwif-cfg.lo \ + libqsesi_la-nwio.lo libqsesi_la-pio.lo libqsesi_la-rwl.lo \ + libqsesi_la-sck.lo libqsesi_la-sio.lo libqsesi_la-task.lo \ + libqsesi_la-thr.lo libqsesi_la-tio.lo libqsesi_la_OBJECTS = $(am_libqsesi_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -459,6 +460,7 @@ libqsesi_la_SOURCES = \ fs-move.c \ glob.c \ intr.c \ + log.c \ mtx.c \ mux.c \ nwad.c \ @@ -583,6 +585,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-fs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-glob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-intr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-log.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-mtx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-mux.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-nwad-skad.Plo@am__quote@ @@ -731,6 +734,13 @@ libqsesi_la-intr.lo: intr.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -c -o libqsesi_la-intr.lo `test -f 'intr.c' || echo '$(srcdir)/'`intr.c +libqsesi_la-log.lo: log.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -MT libqsesi_la-log.lo -MD -MP -MF $(DEPDIR)/libqsesi_la-log.Tpo -c -o libqsesi_la-log.lo `test -f 'log.c' || echo '$(srcdir)/'`log.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsesi_la-log.Tpo $(DEPDIR)/libqsesi_la-log.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='log.c' object='libqsesi_la-log.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -c -o libqsesi_la-log.lo `test -f 'log.c' || echo '$(srcdir)/'`log.c + libqsesi_la-mtx.lo: mtx.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -MT libqsesi_la-mtx.lo -MD -MP -MF $(DEPDIR)/libqsesi_la-mtx.Tpo -c -o libqsesi_la-mtx.lo `test -f 'mtx.c' || echo '$(srcdir)/'`mtx.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsesi_la-mtx.Tpo $(DEPDIR)/libqsesi_la-mtx.Plo diff --git a/qse/lib/si/log.c b/qse/lib/si/log.c new file mode 100644 index 00000000..f17d9416 --- /dev/null +++ b/qse/lib/si/log.c @@ -0,0 +1,560 @@ +/* + * $Id$ + * + Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include "../cmn/mem-prv.h" +#include "../cmn/va_copy.h" + +#if defined(_WIN32) + /* TODO: windows event log */ +#else + #include + #include + #include "../cmn/syscall.h" +#endif + +static const qse_char_t* __priority_names[] = +{ + QSE_T("panic"), + QSE_T("alert"), + QSE_T("critical"), + QSE_T("error"), + QSE_T("warning"), + QSE_T("notice"), + QSE_T("info"), + QSE_T("debug"), + QSE_NULL +}; + +#ifndef LOG_EMERG +# define LOG_EMERG 0 +#endif +#ifndef LOG_ALERT +# define LOG_ALERT 1 +#endif +#ifndef LOG_CRIT +# define LOG_CRIT 2 +#endif +#ifndef LOG_ERR +# define LOG_ERR 3 +#endif +#ifndef LOG_WARNING +# define LOG_WARNING 4 +#endif +#ifndef LOG_NOTICE +# define LOG_NOTICE 5 +#endif +#ifndef LOG_INFO +# define LOG_INFO 6 +#endif +#ifndef LOG_DEBUG +# define LOG_DEBUG 7 +#endif + +static int __syslog_priority[] = +{ + LOG_EMERG, + LOG_ALERT, + LOG_CRIT, + LOG_ERR, + LOG_WARNING, + LOG_NOTICE, + LOG_INFO, + LOG_DEBUG +}; + +#if defined(_WIN32) +/* TODO: windows event logging */ +#else + +struct syslog_fac_info_t +{ + const qse_char_t* name; + qse_log_facility_t code; +}; + +static struct syslog_fac_info_t __syslog_fac_info[] = +{ + { QSE_T("kern"), QSE_LOG_KERN }, + { QSE_T("user"), QSE_LOG_USER }, + { QSE_T("mail"), QSE_LOG_MAIL }, + { QSE_T("daemon"), QSE_LOG_DAEMON }, + { QSE_T("auth"), QSE_LOG_AUTH }, + { QSE_T("syslogd"), QSE_LOG_SYSLOGD }, + { QSE_T("lpr"), QSE_LOG_LPR }, + { QSE_T("news"), QSE_LOG_NEWS }, + { QSE_T("uucp"), QSE_LOG_UUCP }, + { QSE_T("cron"), QSE_LOG_CRON }, + { QSE_T("authpriv"), QSE_LOG_AUTHPRIV }, + { QSE_T("ftp"), QSE_LOG_FTP }, + { QSE_T("local0"), QSE_LOG_LOCAL0 }, + { QSE_T("local1"), QSE_LOG_LOCAL1 }, + { QSE_T("local2"), QSE_LOG_LOCAL2 }, + { QSE_T("local3"), QSE_LOG_LOCAL3 }, + { QSE_T("local4"), QSE_LOG_LOCAL4 }, + { QSE_T("local5"), QSE_LOG_LOCAL5 }, + { QSE_T("local6"), QSE_LOG_LOCAL6 }, + { QSE_T("local7"), QSE_LOG_LOCAL7 }, + + { QSE_NULL, 0 } +}; +#endif + +int qse_log_init (qse_log_t* log, qse_mmgr_t* mmgr, const qse_char_t* ident, int potflags, const qse_log_target_t* target) +{ + QSE_MEMSET (log, 0, QSE_SIZEOF(*log)); + log->mmgr = mmgr; + + log->flags = potflags & (QSE_LOG_MASK_PRIORITY | QSE_LOG_MASK_OPTION); + log->t.syslog_remote.sock = -1; + + if (potflags & QSE_LOG_FILE) + { + qse_strxcpy (log->t.file.path, QSE_COUNTOF(log->t.file.path), target->file); + log->flags |= QSE_LOG_FILE; + } + if (potflags & QSE_LOG_CONSOLE) log->flags |= QSE_LOG_CONSOLE; + if (potflags & QSE_LOG_SYSLOG) log->flags |= QSE_LOG_SYSLOG; + + if (potflags & QSE_LOG_SYSLOG_REMOTE) + { + /* flags_arg should be qse_skad_t* */ + log->t.syslog_remote.addr = target->syslog_remote; + log->flags |= QSE_LOG_SYSLOG_REMOTE; + } + + if (ident) qse_strxcpy (log->ident, QSE_COUNTOF(log->ident), ident); + if (qse_mtx_init(&log->mtx, mmgr) <= -1) return -1; + +#if defined(_WIN32) + /* TODO: windows event logging */ +#else + log->syslog_facility = QSE_LOG_USER; +#endif + + return 0; +} + +void qse_log_fini (qse_log_t* log) +{ + if (log->t.syslog_remote.sock >= 0) + { + QSE_CLOSE (log->t.syslog_remote.sock); + log->t.syslog_remote.sock = -1; + } + + if (log->t.console.sio) + { + qse_sio_close (log->t.console.sio); + log->t.console.sio = QSE_NULL; + } + + if (log->t.file.sio) + { + qse_sio_close (log->t.file.sio); + log->t.file.sio = QSE_NULL; + } + + if (log->t.syslog.opened) + { + closelog (); + log->t.syslog.opened = 0; + } + + if (log->dmsgbuf) + { + qse_mbs_close (log->dmsgbuf); + log->dmsgbuf = QSE_NULL; + } + qse_mtx_fini (&log->mtx); +} + +qse_log_t* qse_log_open (qse_mmgr_t* mmgr, qse_size_t xtnsize, const qse_char_t* ident, int potflags, const qse_log_target_t* target) +{ + qse_log_t* log; + + log = (qse_log_t*) QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_log_t) + xtnsize); + if (log) + { + if (qse_log_init (log, mmgr, ident, potflags, target) <= -1) + { + QSE_MMGR_FREE (mmgr, log); + return QSE_NULL; + } + else QSE_MEMSET (QSE_XTN(log), 0, xtnsize); + } + + return log; +} + +void qse_log_close (qse_log_t* log) +{ + qse_log_fini (log); + QSE_MMGR_FREE (log->mmgr, log); +} + +void qse_log_setident (qse_log_t* log, const qse_char_t* ident) +{ + /* set the base identifer to use */ + if (ident) + qse_strxcpy (log->ident, QSE_COUNTOF(log->ident), ident); + else + log->ident[0] = QSE_T('\0'); + + if (log->t.syslog.opened) + { + closelog (); + log->t.syslog.opened = 0; + /* it will be opened again with the new identifier in the + * output function if necessary. */ + } +} + +void qse_log_settarget (qse_log_t* log, int flags, const qse_log_target_t* target) +{ +#if 0 +/* TODO: */ + if ((log->flags & QSE_LOG_SYSLOG_REMOTE) != 0 && + (flags & QSE_LOG_SYSLOG_REMOTE) == 0) + { + QSE_CLOSE (log->t.syslog_remote.sock); + } + + if ((log->flags & QSE_LOG_SYSLOG_REMOTE) == 0 && + (flags & QSE_LOG_SYSLOG_REMOTE) != 0) + { + int sock; + sock = qse_sckopen (AF_INET, SOCK_DGRAM, 0); + if (sock == -1) flags &= ~QSE_LOG_SYSLOG_REMOTE; + else log->t.syslog_remote.sock = sock; + } + + log->flags &= (QSE_LOG_MASK_PRIORITY | QSE_LOG_MASK_OPTION); /* preserve the priority and the options */ + if (flags & QSE_LOG_FILE) log->flags |= QSE_LOG_FILE; + if (flags & QSE_LOG_CONSOLE) log->flags |= QSE_LOG_CONSOLE; + if (flags & QSE_LOG_SYSLOG) log->flags |= QSE_LOG_SYSLOG; + + if (flags & QSE_LOG_SYSLOG_REMOTE) log->flags |= QSE_LOG_SYSLOG_REMOTE; +#endif + +} + +int qse_log_gettarget (qse_log_t* log, qse_log_target_t* target) +{ + if (target) + { + target->file = log->t.file.path; + target->syslog_remote = log->t.syslog_remote.addr; + } + return log->flags & QSE_LOG_MASK_TARGET; +} + +void qse_log_setpriority (qse_log_t* log, int priority) +{ + log->flags = (log->flags & QSE_LOG_MASK_TARGET) | (priority & QSE_LOG_MASK_PRIORITY); +} + +int qse_log_setprioritybyname (qse_log_t* log, const qse_char_t* name) +{ + const qse_char_t** p = __priority_names; + + while (*p != QSE_NULL) + { + if (qse_strcmp(*p, name) == 0) + { + qse_log_setpriority (log, (int)(p - __priority_names)); + return 0; + } + + p++; + } + + return -1; +} + +void qse_log_setsyslogfacility (qse_log_t* log, qse_log_facility_t facility) +{ +#ifndef _WIN32 + log->syslog_facility = facility; +#endif +} + +int qse_log_setsyslogfacilitybyname (qse_log_t* log, const qse_char_t* name) +{ +#if defined(_WIN32) + /* do nothing */ + return 0; +#else + struct syslog_fac_info_t* f = __syslog_fac_info; + + while (f->name != QSE_NULL) + { + if (qse_strcmp (f->name, name) == 0) + { + log->syslog_facility = f->code; + return 0; + } + + f++; + } + + return -1; +#endif +} + +int qse_log_getpriority (qse_log_t* log) +{ + return log->flags & QSE_LOG_MASK_PRIORITY; +} + +const qse_char_t* qse_log_getpriorityname (qse_log_t* log) +{ + int pri = log->flags & QSE_LOG_MASK_PRIORITY; + + if (pri < 0 || pri >= QSE_COUNTOF(__priority_names)) return QSE_NULL; + return __priority_names[pri]; +} + +static QSE_INLINE void __report_over_sio (qse_log_t* log, qse_sio_t* sio, const qse_mchar_t* tm, const qse_char_t* ident, const qse_char_t* fmt, va_list arg) +{ + int id_out = 0; + + qse_sio_putmbs (sio, tm); + qse_sio_putmbs (sio, QSE_MT(" ")); + + if (log->ident[0] != QSE_T('\0')) + { + qse_sio_putstr (sio, log->ident); + + if (ident && ident[0] != QSE_T('\0')) + { + qse_sio_putmbs (sio, QSE_MT("(")); + qse_sio_putstr (sio, ident); + qse_sio_putmbs (sio, QSE_MT(")")); + } + id_out = 1; + } + else + { + if (ident && ident[0] != QSE_T('\0')) + { + qse_sio_putstr (sio, ident); + id_out = 1; + } + } + + if (id_out) qse_sio_putmbs (sio, QSE_MT(": ")); + + qse_sio_putstrvf (sio, fmt, arg); + qse_sio_putmbs (sio, "\n"); +} + +void qse_log_report (qse_log_t* log, const qse_char_t* ident, int pri, const qse_char_t* fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + qse_log_reportv (log, ident, pri, fmt, ap); + va_end (ap); +} + +void qse_log_reportv (qse_log_t* log, const qse_char_t* ident, int pri, const qse_char_t* fmt, va_list ap) +{ + qse_ntime_t now; + qse_btime_t cnow; + qse_mchar_t tm[64]; + + if ((log->flags & QSE_LOG_MASK_TARGET) == 0) return; /* no target */ + + if (log->flags & QSE_LOG_ENABLE_MASKED) + { + if (!(pri & (log->flags & QSE_LOG_MASK_PRIORITY))) return; + } + else + { + if (pri > (log->flags & QSE_LOG_MASK_PRIORITY)) return; + } + + if (qse_gettime(&now) <= -1) return; + if (qse_localtime(&now, &cnow) <= -1) return; + + if (log->flags & (QSE_LOG_CONSOLE | QSE_LOG_FILE)) + { + if (cnow.gmtoff == QSE_TYPE_MIN(int)) + { + qse_mbsxfmt (tm, QSE_COUNTOF(tm), + QSE_T("%04.4d-%02d-%02d %02d:%02d:%02d"), + cnow.year + QSE_BTIME_YEAR_BASE, cnow.mon + 1, cnow.mday, + cnow.hour, cnow.min, cnow.sec); + } + else + { + qse_long_t gmtoff_hour, gmtoff_min; + gmtoff_hour = cnow.gmtoff / QSE_SECS_PER_HOUR; + gmtoff_min = (cnow.gmtoff % QSE_SECS_PER_HOUR) / QSE_SECS_PER_MIN; + qse_mbsxfmt (tm, QSE_COUNTOF(tm), + QSE_T("%04.4d-%02d-%02d %02d:%02d:%02d %c%02d%02d"), + cnow.year + QSE_BTIME_YEAR_BASE, cnow.mon + 1, cnow.mday, + cnow.hour, cnow.min, cnow.sec, + ((cnow.gmtoff > 0)? QSE_T('+'): QSE_T('-')), + gmtoff_hour, gmtoff_min); + } + } + + if (qse_mtx_lock (&log->mtx, QSE_NULL) <= -1) return; + + if (log->flags & QSE_LOG_CONSOLE) + { + if (!log->t.console.sio) + log->t.console.sio = qse_sio_openstd (log->mmgr, 0, QSE_SIO_STDERR, QSE_SIO_APPEND | QSE_SIO_IGNOREMBWCERR); + if (log->t.console.sio) + { + va_list xap; + va_copy (xap, ap); + __report_over_sio (log, log->t.console.sio, tm, ident, fmt, xap); + } + } + + if (log->flags & QSE_LOG_FILE) + { + if (!log->t.file.sio) + log->t.file.sio = qse_sio_open (log->mmgr, 0, log->t.file.path, QSE_SIO_CREATE | QSE_SIO_APPEND | QSE_SIO_IGNOREMBWCERR); + if (log->t.file.sio) + { + va_list xap; + va_copy (xap, ap); + __report_over_sio (log, log->t.file.sio, tm, ident, fmt, xap); + if (!(log->flags & QSE_LOG_KEEP_FILE_OPEN)) + { + qse_sio_close (log->t.file.sio); + log->t.file.sio = QSE_NULL; + } + } + } + + if (log->flags & (QSE_LOG_SYSLOG | QSE_LOG_SYSLOG_REMOTE)) + { + va_list xap; + + if (!log->dmsgbuf) log->dmsgbuf = qse_mbs_open (log->mmgr, 0, 0); + if (!log->dmsgbuf) goto done; + + va_copy (xap, ap); + if (qse_str_vfmt (log->dmsgbuf, fmt, xap) == QSE_TYPE_MAX(qse_size_t)) goto done; + } + + if (log->flags & QSE_LOG_SYSLOG) + { + #if defined(_WIN32) + /* TODO: windows event log */ + #else + int sl_pri, sl_opt; + + sl_opt = (log->flags & QSE_LOG_SYSLOG_PID)? LOG_PID: 0; + sl_pri = (pri < QSE_COUNTOF(__syslog_priority))? __syslog_priority[pri]: LOG_DEBUG; + + if (!log->t.syslog.opened) + { + /* the secondary 'ident' string is not included into syslog */ + #if defined(QSE_CHAR_IS_MCHAR) + openlog (log->ident, sl_opt, log->syslog_facility); + #else + qse_mchar_t idbuf[QSE_LOG_IDENT_MAX * 2 + 1]; + qse_mbsxfmt (idbuf, QSE_COUNTOF(idbuf), QSE_MT("%ls"), log->ident); + openlog (idbuf, sl_opt, log->syslog_facility); + #endif + log->t.syslog.opened = 1; + } + + syslog (sl_pri, "%s", QSE_MBS_PTR(log->dmsgbuf)); + #endif + } + + /* remote syslogging for ipv4 */ + if (log->flags & QSE_LOG_SYSLOG_REMOTE) + { + #if defined(_WIN32) + /* TODO: windows event log */ + #else + /* direct interface over udp to a remote syslog server */ + +#if 0 + int sl_pri; + + + sl_pri = (pri < QSE_COUNTOF(__syslog_priority))? __syslog_priority[pri]: LOG_DEBUG; + +#if 0 + qse_formattime (tm, QSE_COUNTOF(tm), QSE_T("%b %d %H:%M:%S"), &cnow); +#endif + if (idt == QSE_NULL) + { + qse_strxfmt (log->msgbuf2, QSE_COUNTOF(log->msgbuf2), + QSE_T("<%d>%s %s"), + (int)(log->syslog_facility | sl_pri), + tm, log->msgbuf); + } + else + { + qse_strxfmt (log->msgbuf2, QSE_COUNTOF(log->msgbuf2), + QSE_T("<%d>%s %s: %s"), + (int)(log->syslog_facility | sl_pri), + tm, idt, log->msgbuf); + } + + if (log->t.syslog_remote.sock <= -1) + log->t.syslog_remote.sock = socket (qse_skadfamily(&log->t.syslog_remote.addr), SOCK_DGRAM, 0); + + if (log->t.syslog_remote.sock >= 0) + { + #if defined(QSE_CHAR_IS_MCHAR) + sendto (log->t.syslog_remote.sock, log->msgbuf2, qse_strlen(log->msgbuf2), 0, + (struct sockaddr*)&log->t.syslog_remote.addr, + qse_skadsize(&log->t.syslog_remote.addr)); + #else + qse_wcstomcs (log->msgbuf2, log->msgbuf_mb, QSE_COUNTOF(log->msgbuf_mb)); + + sendto (log->t.syslog_remote.sock, + log->msgbuf_mb, qse_mstrlen(log->msgbuf_mb), 0, + (struct sockaddr*)&log->t.syslog_remote.addr, + qse_skadsize(&log->t.syslog_remote.addr)); + #endif + } +#endif + #endif + } + +done: + qse_mtx_unlock (&log->mtx); +} + +const qse_char_t* qse_get_log_priority_name (int pri) +{ + if (pri < 0 || pri >= QSE_COUNTOF(__priority_names)) return QSE_NULL; + return __priority_names[pri]; +}