EFL 1.7 svn doobies
[profile/ivi/eina.git] / src / lib / eina_log.c
1 /* EINA - EFL data type library
2  * Copyright (C) 2007-2009 Jorge Luis Zapata Muga, Cedric Bail, Andre Dieb
3  * Martins
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library;
17  * if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <fnmatch.h>
28 #include <assert.h>
29 #include <errno.h>
30
31 #if defined HAVE_EXECINFO_H && defined HAVE_BACKTRACE && defined HAVE_BACKTRACE_SYMBOLS
32 # include <execinfo.h>
33 # define EINA_LOG_BACKTRACE
34 #endif
35
36 #ifdef HAVE_UNISTD_H
37 # include <unistd.h>
38 #endif
39
40 #ifdef EFL_HAVE_POSIX_THREADS
41 # include <pthread.h>
42 #endif
43
44 #ifdef HAVE_EVIL
45 # include <Evil.h>
46 #endif
47
48 #include "eina_config.h"
49 #include "eina_private.h"
50 #include "eina_inlist.h"
51
52 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
53 #include "eina_safety_checks.h"
54 #include "eina_log.h"
55
56 /* TODO
57  * + printing logs to stdout or stderr can be implemented
58  * using a queue, useful for multiple threads printing
59  * + add a wrapper for assert?
60  */
61
62 /*============================================================================*
63 *                                  Local                                     *
64 *============================================================================*/
65
66 /**
67  * @cond LOCAL
68  */
69
70 #define EINA_LOG_ENV_ABORT "EINA_LOG_ABORT"
71 #define EINA_LOG_ENV_ABORT_LEVEL "EINA_LOG_ABORT_LEVEL"
72 #define EINA_LOG_ENV_LEVEL "EINA_LOG_LEVEL"
73 #define EINA_LOG_ENV_LEVELS "EINA_LOG_LEVELS"
74 #define EINA_LOG_ENV_LEVELS_GLOB "EINA_LOG_LEVELS_GLOB"
75 #define EINA_LOG_ENV_COLOR_DISABLE "EINA_LOG_COLOR_DISABLE"
76 #define EINA_LOG_ENV_FILE_DISABLE "EINA_LOG_FILE_DISABLE"
77 #define EINA_LOG_ENV_FUNCTION_DISABLE "EINA_LOG_FUNCTION_DISABLE"
78 #define EINA_LOG_ENV_BACKTRACE "EINA_LOG_BACKTRACE"
79
80 #ifdef EINA_ENABLE_LOG
81
82 // Structure for storing domain level settings passed from the command line
83 // that will be matched with application-defined domains.
84 typedef struct _Eina_Log_Domain_Level_Pending Eina_Log_Domain_Level_Pending;
85 struct _Eina_Log_Domain_Level_Pending
86 {
87    EINA_INLIST;
88    unsigned int level;
89    size_t namelen;
90    char name[];
91 };
92
93 /*
94  * List of levels for domains set by the user before the domains are registered,
95  * updates the domain levels on the first log and clears itself.
96  */
97 static Eina_Inlist *_pending_list = NULL;
98 static Eina_Inlist *_glob_list = NULL;
99
100 // Disable color flag (can be changed through the env var
101 // EINA_LOG_ENV_COLOR_DISABLE).
102 static Eina_Bool _disable_color = EINA_FALSE;
103 static Eina_Bool _disable_file = EINA_FALSE;
104 static Eina_Bool _disable_function = EINA_FALSE;
105 static Eina_Bool _abort_on_critical = EINA_FALSE;
106 static int _abort_level_on_critical = EINA_LOG_LEVEL_CRITICAL;
107
108 #ifdef EINA_LOG_BACKTRACE
109 static int _backtrace_level = -1;
110 #endif
111
112 #ifdef EFL_HAVE_THREADS
113
114 static Eina_Bool _threads_enabled = EINA_FALSE;
115 static Eina_Bool _threads_inited = EINA_FALSE;
116
117 # ifdef EFL_HAVE_POSIX_THREADS
118
119 typedef pthread_t Thread;
120
121 static pthread_t _main_thread;
122
123 #  define SELF() pthread_self()
124 #  define IS_MAIN(t)  pthread_equal(t, _main_thread)
125 #  define IS_OTHER(t) EINA_UNLIKELY(!IS_MAIN(t))
126 #  define CHECK_MAIN(...)                                         \
127    do {                                                           \
128       if (!IS_MAIN(pthread_self())) {                             \
129          fprintf(stderr,                                          \
130                  "ERR: not main thread! current=%lu, main=%lu\n", \
131                  (unsigned long)pthread_self(),                   \
132                  (unsigned long)_main_thread);                    \
133          return __VA_ARGS__;                                      \
134       }                                                           \
135    } while (0)
136
137 #  ifdef EFL_HAVE_POSIX_THREADS_SPINLOCK
138
139 static pthread_spinlock_t _log_lock;
140
141 static Eina_Bool _eina_log_spinlock_init(void)
142 {
143    if (pthread_spin_init(&_log_lock, PTHREAD_PROCESS_PRIVATE) == 0)
144      return EINA_TRUE;
145
146    fprintf(stderr,
147            "ERROR: pthread_spin_init(%p, PTHREAD_PROCESS_PRIVATE): %s\n",
148            &_log_lock, strerror(errno));
149    return EINA_FALSE;
150 }
151
152 #   define LOG_LOCK()                                                  \
153    if (_threads_enabled)                                               \
154          do {                                                          \
155             if (0) {                                                   \
156                fprintf(stderr, "+++LOG LOG_LOCKED!   [%s, %lu]\n",     \
157                        __FUNCTION__, (unsigned long)pthread_self()); } \
158             if (EINA_UNLIKELY(_threads_enabled)) {                     \
159                pthread_spin_lock(&_log_lock); }                        \
160          } while (0)
161 #   define LOG_UNLOCK()                                                \
162    if (_threads_enabled)                                               \
163          do {                                                          \
164             if (EINA_UNLIKELY(_threads_enabled)) {                     \
165                pthread_spin_unlock(&_log_lock); }                      \
166             if (0) {                                                   \
167                fprintf(stderr,                                         \
168                        "---LOG LOG_UNLOCKED! [%s, %lu]\n",             \
169                        __FUNCTION__, (unsigned long)pthread_self()); } \
170          } while (0)
171 #   define INIT() _eina_log_spinlock_init()
172 #   define SHUTDOWN() pthread_spin_destroy(&_log_lock)
173
174 #  else /* ! EFL_HAVE_POSIX_THREADS_SPINLOCK */
175
176 static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
177 #   define LOG_LOCK() if(_threads_enabled) {pthread_mutex_lock(&_log_mutex); }
178 #   define LOG_UNLOCK() if(_threads_enabled) {pthread_mutex_unlock(&_log_mutex); }
179 #   define INIT() (1)
180 #   define SHUTDOWN() do {} while (0)
181
182 #  endif /* ! EFL_HAVE_POSIX_THREADS_SPINLOCK */
183
184 # else /* EFL_HAVE_WIN32_THREADS */
185
186 typedef DWORD Thread;
187
188 static DWORD _main_thread;
189
190 #  define SELF() GetCurrentThreadId()
191 #  define IS_MAIN(t)  (t == _main_thread)
192 #  define IS_OTHER(t) EINA_UNLIKELY(!IS_MAIN(t))
193 #  define CHECK_MAIN(...)                                         \
194    do {                                                           \
195       if (!IS_MAIN(GetCurrentThreadId())) {                       \
196          fprintf(stderr,                                          \
197                  "ERR: not main thread! current=%lu, main=%lu\n", \
198                  GetCurrentThreadId(), _main_thread);             \
199          return __VA_ARGS__;                                      \
200       }                                                           \
201    } while (0)
202
203 static HANDLE _log_mutex = NULL;
204
205 #  define LOG_LOCK() if(_threads_enabled) WaitForSingleObject(_log_mutex, INFINITE)
206 #  define LOG_UNLOCK() if(_threads_enabled) ReleaseMutex(_log_mutex)
207 #  define INIT() ((_log_mutex = CreateMutex(NULL, FALSE, NULL)) ? 1 : 0)
208 #  define SHUTDOWN()  if (_log_mutex) CloseHandle(_log_mutex)
209
210 # endif /* EFL_HAVE_WIN32_THREADS */
211
212 #else /* ! EFL_HAVE_THREADS */
213
214 # define LOG_LOCK() do {} while (0)
215 # define LOG_UNLOCK() do {} while (0)
216 # define IS_MAIN(t)  (1)
217 # define IS_OTHER(t) (0)
218 # define CHECK_MAIN(...) do {} while (0)
219 # define INIT() (1)
220 # define SHUTDOWN() do {} while (0)
221
222 #endif /* ! EFL_HAVE_THREADS */
223
224
225 // List of domains registered
226 static Eina_Log_Domain *_log_domains = NULL;
227 static unsigned int _log_domains_count = 0;
228 static size_t _log_domains_allocated = 0;
229
230 // Default function for printing on domains
231 static Eina_Log_Print_Cb _print_cb = eina_log_print_cb_stderr;
232 static void *_print_cb_data = NULL;
233
234 #ifdef DEBUG
235 static Eina_Log_Level _log_level = EINA_LOG_LEVEL_DBG;
236 #elif DEBUG_CRITICAL
237 static Eina_Log_Level _log_level = EINA_LOG_LEVEL_CRITICAL;
238 #else
239 static Eina_Log_Level _log_level = EINA_LOG_LEVEL_ERR;
240 #endif
241
242 /* NOTE: if you change this, also change:
243  *   eina_log_print_level_name_get()
244  *   eina_log_print_level_name_color_get()
245  */
246 static const char *_names[] = {
247    "CRI",
248    "ERR",
249    "WRN",
250    "INF",
251    "DBG",
252 };
253
254 #ifdef _WIN32
255 /* TODO: query win32_def_attr on eina_log_init() */
256 static int win32_def_attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
257
258 /* NOTE: can't use eina_log from inside this function */
259 static int
260 eina_log_win32_color_convert(const char *color, const char **endptr)
261 {
262    const char *p;
263    int attr = 0;
264
265    if (endptr) *endptr = color;
266
267    if (color[0] != '\033') return 0;
268    if (color[1] != '[') return 0;
269
270    p = color + 2;
271    while (1)
272      {
273         char *end;
274         int code = strtol(p, &end, 10);
275
276         if (p == end)
277           {
278              //fputs("empty color string\n", stderr);
279              if (endptr) *endptr = end;
280              attr = 0; /* assume it was not color, must end with 'm' */
281              break;
282           }
283
284         if (code)
285           {
286              if (code == 0) attr = win32_def_attr;
287              else if (code == 1) attr |= FOREGROUND_INTENSITY;
288              else if (code == 4) attr |= COMMON_LVB_UNDERSCORE;
289              else if (code == 7) attr |= COMMON_LVB_REVERSE_VIDEO;
290              else if ((code >= 30) && (code <= 37))
291                {
292                   /* clear foreground */
293                   attr &= ~(FOREGROUND_RED |
294                             FOREGROUND_GREEN |
295                             FOREGROUND_BLUE);
296
297                   if (code == 31)
298                     attr |= FOREGROUND_RED;
299                   else if (code == 32)
300                     attr |= FOREGROUND_GREEN;
301                   else if (code == 33)
302                     attr |= FOREGROUND_RED | FOREGROUND_GREEN;
303                   else if (code == 34)
304                     attr |= FOREGROUND_BLUE;
305                   else if (code == 35)
306                     attr |= FOREGROUND_RED | FOREGROUND_BLUE;
307                   else if (code == 36)
308                     attr |= FOREGROUND_GREEN | FOREGROUND_BLUE;
309                   else if (code == 37)
310                     attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
311                }
312              else if ((code >= 40) && (code <= 47))
313                {
314                   /* clear background */
315                   attr &= ~(BACKGROUND_RED |
316                             BACKGROUND_GREEN |
317                             BACKGROUND_BLUE);
318
319                   if (code == 41)
320                     attr |= BACKGROUND_RED;
321                   else if (code == 42)
322                     attr |= BACKGROUND_GREEN;
323                   else if (code == 44)
324                     attr |= BACKGROUND_RED | BACKGROUND_GREEN;
325                   else if (code == 44)
326                     attr |= BACKGROUND_BLUE;
327                   else if (code == 45)
328                     attr |= BACKGROUND_RED | BACKGROUND_BLUE;
329                   else if (code == 46)
330                     attr |= BACKGROUND_GREEN | BACKGROUND_BLUE;
331                   else if (code == 47)
332                     attr |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
333                }
334           }
335
336         if (*end == 'm')
337           {
338              if (endptr) *endptr = end + 1;
339              break;
340           }
341         else if (*end == ';')
342           p = end + 1;
343         else
344           {
345              //fprintf(stderr, "unexpected char in color string: %s\n", end);
346              attr = 0; /* assume it was not color */
347              if (endptr) *endptr = end;
348              break;
349           }
350      }
351
352    return attr;
353 }
354
355 static int
356 eina_log_win32_color_get(const char *color)
357 {
358    return eina_log_win32_color_convert(color, NULL);
359 }
360 #endif
361
362 static inline unsigned int
363 eina_log_pid_get(void)
364 {
365    return (unsigned int)getpid();
366 }
367
368 static inline void
369 eina_log_print_level_name_get(int level, const char **p_name)
370 {
371    static char buf[4];
372    /* NOTE: if you change this, also change
373     *    eina_log_print_level_name_color_get()
374     *    eina_log_level_name_get() (at eina_inline_log.x)
375     */
376    if (EINA_UNLIKELY(level < 0))
377      {
378         snprintf(buf, sizeof(buf), "%03d", level);
379         *p_name = buf;
380      }
381    else if (EINA_UNLIKELY(level >= EINA_LOG_LEVELS))
382      {
383         snprintf(buf, sizeof(buf), "%03d", level);
384         *p_name = buf;
385      }
386    else
387       *p_name = _names[level];
388 }
389
390 #ifdef _WIN32
391 static inline void
392 eina_log_print_level_name_color_get(int level,
393                                     const char **p_name,
394                                     int *p_color)
395 {
396    static char buf[4];
397    /* NOTE: if you change this, also change:
398     *   eina_log_print_level_name_get()
399     */
400    if (EINA_UNLIKELY(level < 0))
401      {
402         snprintf(buf, sizeof(buf), "%03d", level);
403         *p_name = buf;
404      }
405    else if (EINA_UNLIKELY(level >= EINA_LOG_LEVELS))
406      {
407         snprintf(buf, sizeof(buf), "%03d", level);
408         *p_name = buf;
409      }
410    else
411       *p_name = _names[level];
412
413    *p_color = eina_log_win32_color_get(eina_log_level_color_get(level));
414 }
415 #else
416 static inline void
417 eina_log_print_level_name_color_get(int level,
418                                     const char **p_name,
419                                     const char **p_color)
420 {
421    static char buf[4];
422    /* NOTE: if you change this, also change:
423     *   eina_log_print_level_name_get()
424     */
425    if (EINA_UNLIKELY(level < 0))
426      {
427         snprintf(buf, sizeof(buf), "%03d", level);
428         *p_name = buf;
429      }
430    else if (EINA_UNLIKELY(level >= EINA_LOG_LEVELS))
431      {
432         snprintf(buf, sizeof(buf), "%03d", level);
433         *p_name = buf;
434      }
435    else
436       *p_name = _names[level];
437
438    *p_color = eina_log_level_color_get(level);
439 }
440 #endif
441
442 #define DECLARE_LEVEL_NAME(level) const char *name; \
443    eina_log_print_level_name_get(level, &name)
444 #ifdef _WIN32
445 # define DECLARE_LEVEL_NAME_COLOR(level) const char *name; int color; \
446    eina_log_print_level_name_color_get(level, &name, &color)
447 #else
448 # define DECLARE_LEVEL_NAME_COLOR(level) const char *name, *color; \
449    eina_log_print_level_name_color_get(level, &name, &color)
450 #endif
451
452 /** No threads, No color */
453 static void
454 eina_log_print_prefix_NOthreads_NOcolor_file_func(FILE *fp,
455                                                   const Eina_Log_Domain *d,
456                                                   Eina_Log_Level level,
457                                                   const char *file,
458                                                   const char *fnc,
459                                                   int line)
460 {
461    DECLARE_LEVEL_NAME(level);
462    fprintf(fp, "%s<%u>:%s %s:%d %s() ", name, eina_log_pid_get(), 
463            d->domain_str, file, line, fnc);
464 }
465
466 static void
467 eina_log_print_prefix_NOthreads_NOcolor_NOfile_func(FILE *fp,
468                                                     const Eina_Log_Domain *d,
469                                                     Eina_Log_Level level,
470                                                     const char *file __UNUSED__,
471                                                     const char *fnc,
472                                                     int line __UNUSED__)
473 {
474    DECLARE_LEVEL_NAME(level);
475    fprintf(fp, "%s<%u>:%s %s() ", name, eina_log_pid_get(), d->domain_str, 
476            fnc);
477 }
478
479 static void
480 eina_log_print_prefix_NOthreads_NOcolor_file_NOfunc(FILE *fp,
481                                                     const Eina_Log_Domain *d,
482                                                     Eina_Log_Level level,
483                                                     const char *file,
484                                                     const char *fnc __UNUSED__,
485                                                     int line)
486 {
487    DECLARE_LEVEL_NAME(level);
488    fprintf(fp, "%s<%u>:%s %s:%d ", name, eina_log_pid_get(), d->domain_str, 
489            file, line);
490 }
491
492 /* No threads, color */
493 static void
494 eina_log_print_prefix_NOthreads_color_file_func(FILE *fp,
495                                                 const Eina_Log_Domain *d,
496                                                 Eina_Log_Level level,
497                                                 const char *file,
498                                                 const char *fnc,
499                                                 int line)
500 {
501    DECLARE_LEVEL_NAME_COLOR(level);
502 #ifdef _WIN32_WCE
503    fprintf(fp, "%s<%u>:%s %s:%d %s() ", name, eina_log_pid_get(), 
504            d->domain_str, file, line, fnc);
505 #elif _WIN32
506    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
507                            color);
508    fprintf(fp, "%s", name);
509    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
510                            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
511    fprintf(fp, ":");
512    SetConsoleTextAttribute(GetStdHandle(
513                               STD_OUTPUT_HANDLE),
514                            eina_log_win32_color_get(d->domain_str));
515    fprintf(fp, "%s", d->name);
516    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
517                            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
518    fprintf(fp, " %s:%d ", file, line);
519    SetConsoleTextAttribute(GetStdHandle(
520                               STD_OUTPUT_HANDLE),
521                            FOREGROUND_INTENSITY | FOREGROUND_RED |
522                            FOREGROUND_GREEN | FOREGROUND_BLUE);
523    fprintf(fp, "%s()", fnc);
524    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
525                            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
526    fprintf(fp, " ");
527 #else
528    fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s %s:%d "
529            EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
530            color, name, eina_log_pid_get(), d->domain_str, file, line, fnc);
531 #endif
532 }
533
534 static void
535 eina_log_print_prefix_NOthreads_color_NOfile_func(FILE *fp,
536                                                   const Eina_Log_Domain *d,
537                                                   Eina_Log_Level level,
538                                                   const char *file __UNUSED__,
539                                                   const char *fnc,
540                                                   int line __UNUSED__)
541 {
542    DECLARE_LEVEL_NAME_COLOR(level);
543 #ifdef _WIN32_WCE
544    fprintf(fp, "%s<%u>:%s %s() ", name, eina_log_pid_get(), d->domain_str, 
545            fnc);
546 #elif _WIN32
547    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
548                            color);
549    fprintf(fp, "%s", name);
550    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
551                            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
552    fprintf(fp, ":");
553    SetConsoleTextAttribute(GetStdHandle(
554                               STD_OUTPUT_HANDLE),
555                            eina_log_win32_color_get(d->domain_str));
556    fprintf(fp, "%s", d->name);
557    SetConsoleTextAttribute(GetStdHandle(
558                               STD_OUTPUT_HANDLE),
559                            FOREGROUND_INTENSITY | FOREGROUND_RED |
560                            FOREGROUND_GREEN | FOREGROUND_BLUE);
561    fprintf(fp, "%s()", fnc);
562    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
563                            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
564    fprintf(fp, " ");
565 #else
566    fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s "
567            EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
568            color, name, eina_log_pid_get(), d->domain_str, fnc);
569 #endif
570 }
571
572 static void
573 eina_log_print_prefix_NOthreads_color_file_NOfunc(FILE *fp,
574                                                   const Eina_Log_Domain *d,
575                                                   Eina_Log_Level level,
576                                                   const char *file,
577                                                   const char *fnc __UNUSED__,
578                                                   int line)
579 {
580    DECLARE_LEVEL_NAME_COLOR(level);
581 #ifdef _WIN32_WCE
582    fprintf(fp, "%s<%u>:%s %s:%d ", name, eina_log_pid_get(), d->domain_str, 
583            file, line);
584 #elif _WIN32
585    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
586                            color);
587    fprintf(fp, "%s", name);
588    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
589                            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
590    fprintf(fp, ":");
591    SetConsoleTextAttribute(GetStdHandle(
592                               STD_OUTPUT_HANDLE),
593                            eina_log_win32_color_get(d->domain_str));
594    fprintf(fp, "%s", d->name);
595    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
596                            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
597    fprintf(fp, " %s:%d ", file, line);
598 #else
599    fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s %s:%d ",
600            color, name, eina_log_pid_get(), d->domain_str, file, line);
601 #endif
602 }
603
604 /** threads, No color */
605 #ifdef EFL_HAVE_THREADS
606 static void
607 eina_log_print_prefix_threads_NOcolor_file_func(FILE *fp,
608                                                 const Eina_Log_Domain *d,
609                                                 Eina_Log_Level level,
610                                                 const char *file,
611                                                 const char *fnc,
612                                                 int line)
613 {
614    Thread cur;
615
616    DECLARE_LEVEL_NAME(level);
617    cur = SELF();
618    if (IS_OTHER(cur))
619      {
620         fprintf(fp, "%s<%u>:%s[T:%lu] %s:%d %s() ",
621                 name, eina_log_pid_get(), d->domain_str, 
622                 (unsigned long)cur, file, line, fnc);
623         return;
624      }
625    fprintf(fp, "%s<%u>:%s %s:%d %s() ", 
626            name, eina_log_pid_get(), d->domain_str, file, line, fnc);
627 }
628
629 static void
630 eina_log_print_prefix_threads_NOcolor_NOfile_func(FILE *fp,
631                                                   const Eina_Log_Domain *d,
632                                                   Eina_Log_Level level,
633                                                   const char *file __UNUSED__,
634                                                   const char *fnc,
635                                                   int line __UNUSED__)
636 {
637    Thread cur;
638
639    DECLARE_LEVEL_NAME(level);
640    cur = SELF();
641    if (IS_OTHER(cur))
642      {
643         fprintf(fp, "%s<%u>:%s[T:%lu] %s() ",
644                 name, eina_log_pid_get(), d->domain_str, 
645                 (unsigned long)cur, fnc);
646         return;
647      }
648    fprintf(fp, "%s<%u>:%s %s() ", 
649            name, eina_log_pid_get(), d->domain_str, fnc);
650 }
651
652 static void
653 eina_log_print_prefix_threads_NOcolor_file_NOfunc(FILE *fp,
654                                                   const Eina_Log_Domain *d,
655                                                   Eina_Log_Level level,
656                                                   const char *file,
657                                                   const char *fnc __UNUSED__,
658                                                   int line)
659 {
660    Thread cur;
661
662    DECLARE_LEVEL_NAME(level);
663    cur = SELF();
664    if (IS_OTHER(cur))
665      {
666         fprintf(fp, "%s<%u>:%s[T:%lu] %s:%d ",
667                 name, eina_log_pid_get(), d->domain_str, (unsigned long)cur, 
668                 file, line);
669         return;
670      }
671    
672    fprintf(fp, "%s<%u>:%s %s:%d ", 
673            name, eina_log_pid_get(), d->domain_str, file, line);
674 }
675
676 /* threads, color */
677 static void
678 eina_log_print_prefix_threads_color_file_func(FILE *fp,
679                                               const Eina_Log_Domain *d,
680                                               Eina_Log_Level level,
681                                               const char *file,
682                                               const char *fnc,
683                                               int line)
684 {
685    Thread cur;
686
687    DECLARE_LEVEL_NAME_COLOR(level);
688    cur = SELF();
689    if (IS_OTHER(cur))
690      {
691 # ifdef _WIN32
692         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
693                                 color);
694         fprintf(fp, "%s", name);
695         SetConsoleTextAttribute(GetStdHandle(
696                                    STD_OUTPUT_HANDLE),
697                                 FOREGROUND_RED | FOREGROUND_GREEN |
698                                 FOREGROUND_BLUE);
699         fprintf(fp, ":");
700         SetConsoleTextAttribute(GetStdHandle(
701                                    STD_OUTPUT_HANDLE),
702                                 eina_log_win32_color_get(d->domain_str));
703         fprintf(fp, "%s[T:", d->name);
704         SetConsoleTextAttribute(GetStdHandle(
705                                    STD_OUTPUT_HANDLE),
706                                 FOREGROUND_RED | FOREGROUND_GREEN |
707                                 FOREGROUND_BLUE);
708         fprintf(fp, "[T:");
709         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
710                                 FOREGROUND_GREEN | FOREGROUND_BLUE);
711         fprintf(fp, "%lu", (unsigned long)cur);
712         SetConsoleTextAttribute(GetStdHandle(
713                                    STD_OUTPUT_HANDLE),
714                                 FOREGROUND_RED | FOREGROUND_GREEN |
715                                 FOREGROUND_BLUE);
716         fprintf(fp, "] %s:%d ", file, line);
717         SetConsoleTextAttribute(GetStdHandle(
718                                    STD_OUTPUT_HANDLE),
719                                 FOREGROUND_INTENSITY | FOREGROUND_RED |
720                                 FOREGROUND_GREEN | FOREGROUND_BLUE);
721         fprintf(fp, "%s()", fnc);
722         SetConsoleTextAttribute(GetStdHandle(
723                                    STD_OUTPUT_HANDLE),
724                                 FOREGROUND_RED | FOREGROUND_GREEN |
725                                 FOREGROUND_BLUE);
726         fprintf(fp, " ");
727 # else
728         fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s[T:"
729                 EINA_COLOR_ORANGE "%lu" EINA_COLOR_RESET "] %s:%d "
730                 EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
731                 color, name, eina_log_pid_get() ,d->domain_str, 
732                 (unsigned long)cur, file, line, fnc);
733 # endif
734         return;
735      }
736
737 # ifdef _WIN32
738    eina_log_print_prefix_NOthreads_color_file_func(fp,
739                                                    d,
740                                                    level,
741                                                    file,
742                                                    fnc,
743                                                    line);
744 # else
745    fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s %s:%d "
746            EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
747            color, name, eina_log_pid_get(), d->domain_str, file, line, fnc);
748 # endif
749 }
750
751 static void
752 eina_log_print_prefix_threads_color_NOfile_func(FILE *fp,
753                                                 const Eina_Log_Domain *d,
754                                                 Eina_Log_Level level,
755                                                 const char *file __UNUSED__,
756                                                 const char *fnc,
757                                                 int line __UNUSED__)
758 {
759    Thread cur;
760
761    DECLARE_LEVEL_NAME_COLOR(level);
762    cur = SELF();
763    if (IS_OTHER(cur))
764      {
765 # ifdef _WIN32
766         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
767                                 color);
768         fprintf(fp, "%s", name);
769         SetConsoleTextAttribute(GetStdHandle(
770                                    STD_OUTPUT_HANDLE),
771                                 FOREGROUND_RED | FOREGROUND_GREEN |
772                                 FOREGROUND_BLUE);
773         fprintf(fp, ":");
774         SetConsoleTextAttribute(GetStdHandle(
775                                    STD_OUTPUT_HANDLE),
776                                 eina_log_win32_color_get(d->domain_str));
777         fprintf(fp, "%s[T:", d->name);
778         SetConsoleTextAttribute(GetStdHandle(
779                                    STD_OUTPUT_HANDLE),
780                                 FOREGROUND_RED | FOREGROUND_GREEN |
781                                 FOREGROUND_BLUE);
782         fprintf(fp, "[T:");
783         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
784                                 FOREGROUND_GREEN | FOREGROUND_BLUE);
785         fprintf(fp, "%lu", (unsigned long)cur);
786         SetConsoleTextAttribute(GetStdHandle(
787                                    STD_OUTPUT_HANDLE),
788                                 FOREGROUND_INTENSITY | FOREGROUND_RED |
789                                 FOREGROUND_GREEN | FOREGROUND_BLUE);
790         fprintf(fp, "%s()", fnc);
791         SetConsoleTextAttribute(GetStdHandle(
792                                    STD_OUTPUT_HANDLE),
793                                 FOREGROUND_RED | FOREGROUND_GREEN |
794                                 FOREGROUND_BLUE);
795         fprintf(fp, " ");
796 # else
797         fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s[T:"
798                 EINA_COLOR_ORANGE "%lu" EINA_COLOR_RESET "] "
799                 EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
800                 color, name, eina_log_pid_get(), d->domain_str, 
801                 (unsigned long)cur, fnc);
802 # endif
803         return;
804      }
805
806 # ifdef _WIN32
807    eina_log_print_prefix_NOthreads_color_NOfile_func(fp,
808                                                      d,
809                                                      level,
810                                                      file,
811                                                      fnc,
812                                                      line);
813 # else
814    fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s "
815            EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
816            color, name, eina_log_pid_get(), d->domain_str, fnc);
817 # endif
818 }
819
820 static void
821 eina_log_print_prefix_threads_color_file_NOfunc(FILE *fp,
822                                                 const Eina_Log_Domain *d,
823                                                 Eina_Log_Level level,
824                                                 const char *file,
825                                                 const char *fnc __UNUSED__,
826                                                 int line)
827 {
828    Thread cur;
829
830    DECLARE_LEVEL_NAME_COLOR(level);
831    cur = SELF();
832    if (IS_OTHER(cur))
833      {
834 # ifdef _WIN32
835         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
836                                 color);
837         fprintf(fp, "%s", name);
838         SetConsoleTextAttribute(GetStdHandle(
839                                    STD_OUTPUT_HANDLE),
840                                 FOREGROUND_RED | FOREGROUND_GREEN |
841                                 FOREGROUND_BLUE);
842         fprintf(fp, ":");
843         SetConsoleTextAttribute(GetStdHandle(
844                                    STD_OUTPUT_HANDLE),
845                                 eina_log_win32_color_get(d->domain_str));
846         fprintf(fp, "%s[T:", d->name);
847         SetConsoleTextAttribute(GetStdHandle(
848                                    STD_OUTPUT_HANDLE),
849                                 FOREGROUND_RED | FOREGROUND_GREEN |
850                                 FOREGROUND_BLUE);
851         fprintf(fp, "[T:");
852         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
853                                 FOREGROUND_GREEN | FOREGROUND_BLUE);
854         fprintf(fp, "%lu", (unsigned long)cur);
855         SetConsoleTextAttribute(GetStdHandle(
856                                    STD_OUTPUT_HANDLE),
857                                 FOREGROUND_RED | FOREGROUND_GREEN |
858                                 FOREGROUND_BLUE);
859         fprintf(fp, "] %s:%d ", file, line);
860 # else
861         fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s[T:"
862                 EINA_COLOR_ORANGE "%lu" EINA_COLOR_RESET "] %s:%d ",
863                 color, name, eina_log_pid_get(), d->domain_str, 
864                 (unsigned long)cur, file, line);
865 # endif
866         return;
867      }
868
869 # ifdef _WIN32
870    eina_log_print_prefix_NOthreads_color_file_NOfunc(fp,
871                                                      d,
872                                                      level,
873                                                      file,
874                                                      fnc,
875                                                      line);
876 # else
877         fprintf(fp, "%s%s" EINA_COLOR_RESET ":%s %s:%d ",
878            color, name, d->domain_str, file, line);
879 # endif
880 }
881 #endif /* EFL_HAVE_THREADS */
882
883 static void (*_eina_log_print_prefix)(FILE *fp, const Eina_Log_Domain *d,
884                                       Eina_Log_Level level, const char *file,
885                                       const char *fnc,
886                                       int line) =
887    eina_log_print_prefix_NOthreads_color_file_func;
888
889 static inline void
890 eina_log_print_prefix_update(void)
891 {
892    if (_disable_file && _disable_function)
893      {
894         fprintf(stderr, "ERROR: cannot have " EINA_LOG_ENV_FILE_DISABLE " and "
895                 EINA_LOG_ENV_FUNCTION_DISABLE " set at the same time, will "
896                                               "just disable function.\n");
897         _disable_file = 0;
898      }
899
900 #define S(NOthread, NOcolor, NOfile, NOfunc) \
901    _eina_log_print_prefix = \
902       eina_log_print_prefix_ ## NOthread ## threads_ ## NOcolor ## color_ ## \
903       NOfile \
904       ## file_ ## NOfunc ## func
905
906 #ifdef EFL_HAVE_THREADS
907    if (_threads_enabled)
908      {
909         if (_disable_color)
910           {
911              if (_disable_file)
912                 S(,NO,NO,);
913              else if (_disable_function)
914                 S(,NO,,NO);
915              else
916                 S(,NO,,);
917           }
918         else
919           {
920              if (_disable_file)
921                 S(,,NO,);
922              else if (_disable_function)
923                 S(,,,NO);
924              else
925                 S(,,,);
926           }
927
928         return;
929      }
930
931 #endif
932
933    if (_disable_color)
934      {
935         if (_disable_file)
936                 S(NO,NO,NO,);
937         else if (_disable_function)
938                 S(NO,NO,,NO);
939         else
940                 S(NO,NO,,);
941      }
942    else
943      {
944         if (_disable_file)
945                 S(NO,,NO,);
946         else if (_disable_function)
947                 S(NO,,,NO);
948         else
949                 S(NO,,,);
950      }
951
952 #undef S
953 }
954
955 /*
956  * Creates a colored domain name string.
957  */
958 static const char *
959 eina_log_domain_str_get(const char *name, const char *color)
960 {
961    const char *d;
962
963    if (color)
964      {
965         size_t name_len;
966         size_t color_len;
967
968         name_len = strlen(name);
969         color_len = strlen(color);
970         d =
971            malloc(sizeof(char) *
972                   (color_len + name_len + strlen(EINA_COLOR_RESET) + 1));
973         if (!d)
974            return NULL;
975
976                memcpy((char *)d,                          color, color_len);
977                memcpy((char *)(d + color_len),            name,  name_len);
978                memcpy((char *)(d + color_len + name_len), EINA_COLOR_RESET,
979                strlen(EINA_COLOR_RESET));
980         ((char *)d)[color_len + name_len + strlen(EINA_COLOR_RESET)] = '\0';
981      }
982    else
983       d = strdup(name);
984
985    return d;
986 }
987
988 /*
989  * Setups a new logging domain to the name and color specified. Note that this
990  * constructor acts upon an pre-allocated object.
991  */
992 static Eina_Log_Domain *
993 eina_log_domain_new(Eina_Log_Domain *d, const char *name, const char *color)
994 {
995    EINA_SAFETY_ON_NULL_RETURN_VAL(d,    NULL);
996    EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
997
998    d->level = EINA_LOG_LEVEL_UNKNOWN;
999    d->deleted = EINA_FALSE;
1000
1001    if ((color) && (!_disable_color))
1002       d->domain_str = eina_log_domain_str_get(name, color);
1003    else
1004       d->domain_str = eina_log_domain_str_get(name, NULL);
1005
1006    d->name = strdup(name);
1007    d->namelen = strlen(name);
1008
1009    return d;
1010 }
1011
1012 /*
1013  * Frees internal strings of a log domain, keeping the log domain itself as a
1014  * slot for next domain registers.
1015  */
1016 static void
1017 eina_log_domain_free(Eina_Log_Domain *d)
1018 {
1019    EINA_SAFETY_ON_NULL_RETURN(d);
1020
1021    if (d->domain_str)
1022       free((char *)d->domain_str);
1023
1024    if (d->name)
1025       free((char *)d->name);
1026 }
1027
1028 /*
1029  * Parses domain levels passed through the env var.
1030  */
1031 static void
1032 eina_log_domain_parse_pendings(void)
1033 {
1034    const char *start;
1035
1036    if (!(start = getenv(EINA_LOG_ENV_LEVELS)))
1037       return;
1038
1039    // name1:level1,name2:level2,name3:level3,...
1040    while (1)
1041      {
1042         Eina_Log_Domain_Level_Pending *p;
1043         char *end = NULL;
1044         char *tmp = NULL;
1045         long int level;
1046
1047         end = strchr(start, ':');
1048         if (!end)
1049            break;
1050
1051         // Parse level, keep going if failed
1052         level = strtol((char *)(end + 1), &tmp, 10);
1053         if (tmp == (end + 1))
1054            goto parse_end;
1055
1056         // Parse name
1057         p = malloc(sizeof(Eina_Log_Domain_Level_Pending) + end - start + 1);
1058         if (!p)
1059            break;
1060
1061         p->namelen = end - start;
1062         memcpy((char *)p->name, start, end - start);
1063         ((char *)p->name)[end - start] = '\0';
1064         p->level = level;
1065
1066         _pending_list = eina_inlist_append(_pending_list, EINA_INLIST_GET(p));
1067
1068 parse_end:
1069         start = strchr(tmp, ',');
1070         if (start)
1071            start++;
1072         else
1073            break;
1074      }
1075 }
1076
1077 static void
1078 eina_log_domain_parse_pending_globs(void)
1079 {
1080    const char *start;
1081
1082    if (!(start = getenv(EINA_LOG_ENV_LEVELS_GLOB)))
1083       return;
1084
1085    // name1:level1,name2:level2,name3:level3,...
1086    while (1)
1087      {
1088         Eina_Log_Domain_Level_Pending *p;
1089         char *end = NULL;
1090         char *tmp = NULL;
1091         long int level;
1092
1093         end = strchr(start, ':');
1094         if (!end)
1095            break;
1096
1097         // Parse level, keep going if failed
1098         level = strtol((char *)(end + 1), &tmp, 10);
1099         if (tmp == (end + 1))
1100            goto parse_end;
1101
1102         // Parse name
1103         p = malloc(sizeof(Eina_Log_Domain_Level_Pending) + end - start + 1);
1104         if (!p)
1105            break;
1106
1107         p->namelen = 0; /* not that useful */
1108         memcpy((char *)p->name, start, end - start);
1109         ((char *)p->name)[end - start] = '\0';
1110         p->level = level;
1111
1112         _glob_list = eina_inlist_append(_glob_list, EINA_INLIST_GET(p));
1113
1114 parse_end:
1115         start = strchr(tmp, ',');
1116         if (start)
1117            start++;
1118         else
1119            break;
1120      }
1121 }
1122
1123 static inline int
1124 eina_log_domain_register_unlocked(const char *name, const char *color)
1125 {
1126    Eina_Log_Domain_Level_Pending *pending = NULL;
1127    size_t namelen;
1128    unsigned int i;
1129
1130    for (i = 0; i < _log_domains_count; i++)
1131      {
1132         if (_log_domains[i].deleted)
1133           {
1134              // Found a flagged slot, free domain_str and replace slot
1135              eina_log_domain_new(&_log_domains[i], name, color);
1136              goto finish_register;
1137           }
1138      }
1139
1140    if (_log_domains_count >= _log_domains_allocated)
1141      {
1142         Eina_Log_Domain *tmp;
1143         size_t size;
1144
1145         if (!_log_domains)
1146            // special case for init, eina itself will allocate a dozen of domains
1147            size = 24;
1148         else
1149            // grow 8 buckets to minimize reallocs
1150            size = _log_domains_allocated + 8;
1151
1152         tmp = realloc(_log_domains, sizeof(Eina_Log_Domain) * size);
1153
1154         if (tmp)
1155           {
1156              // Success!
1157              _log_domains = tmp;
1158              _log_domains_allocated = size;
1159           }
1160         else
1161            return -1;
1162      }
1163
1164    // Use an allocated slot
1165              eina_log_domain_new(&_log_domains[i], name, color);
1166    _log_domains_count++;
1167
1168 finish_register:
1169    namelen = _log_domains[i].namelen;
1170
1171    EINA_INLIST_FOREACH(_pending_list, pending)
1172    {
1173       if ((namelen == pending->namelen) && (strcmp(pending->name, name) == 0))
1174         {
1175            _log_domains[i].level = pending->level;
1176            break;
1177         }
1178    }
1179
1180    if (_log_domains[i].level == EINA_LOG_LEVEL_UNKNOWN)
1181      {
1182         EINA_INLIST_FOREACH(_glob_list, pending)
1183         {
1184            if (!fnmatch(pending->name, name, 0))
1185              {
1186                 _log_domains[i].level = pending->level;
1187                 break;
1188              }
1189         }
1190      }
1191
1192    // Check if level is still UNKNOWN, set it to global
1193    if (_log_domains[i].level == EINA_LOG_LEVEL_UNKNOWN)
1194       _log_domains[i].level = _log_level;
1195
1196    return i;
1197 }
1198
1199 static inline Eina_Bool
1200 eina_log_term_color_supported(const char *term)
1201 {
1202    const char *tail;
1203
1204    if (!term)
1205       return EINA_FALSE;
1206
1207    tail = term + 1;
1208    switch (term[0])
1209      {
1210       /* list of known to support color terminals,
1211        * take from gentoo's portage.
1212        */
1213
1214       case 'x': /* xterm and xterm-color */
1215          return ((strncmp(tail, "term", sizeof("term") - 1) == 0) &&
1216                  ((tail[sizeof("term") - 1] == '\0') ||
1217                   (strcmp(tail + sizeof("term") - 1, "-color") == 0)));
1218
1219       case 'E': /* Eterm */
1220       case 'a': /* aterm */
1221       case 'k': /* kterm */
1222          return (strcmp(tail, "term") == 0);
1223
1224       case 'r': /* xrvt or rxvt-unicode */
1225          return ((strncmp(tail, "xvt", sizeof("xvt") - 1) == 0) &&
1226                  ((tail[sizeof("xvt") - 1] == '\0') ||
1227                   (strcmp(tail + sizeof("xvt") - 1, "-unicode") == 0)));
1228
1229       case 's': /* screen */
1230          return (strcmp(tail, "creen") == 0);
1231
1232       case 'g': /* gnome */
1233          return (strcmp(tail, "nome") == 0);
1234
1235       case 'i': /* interix */
1236          return (strcmp(tail, "nterix") == 0);
1237
1238       default:
1239          return EINA_FALSE;
1240      }
1241 }
1242
1243 static inline void
1244 eina_log_domain_unregister_unlocked(int domain)
1245 {
1246    Eina_Log_Domain *d;
1247
1248    if ((unsigned int)domain >= _log_domains_count)
1249       return;
1250
1251    d = &_log_domains[domain];
1252    eina_log_domain_free(d);
1253    d->deleted = 1;
1254 }
1255
1256 static inline void
1257 eina_log_print_unlocked(int domain,
1258                         Eina_Log_Level level,
1259                         const char *file,
1260                         const char *fnc,
1261                         int line,
1262                         const char *fmt,
1263                         va_list args)
1264 {
1265    Eina_Log_Domain *d;
1266
1267 #ifdef EINA_SAFETY_CHECKS
1268    if (EINA_UNLIKELY((unsigned int)domain >= _log_domains_count) ||
1269        EINA_UNLIKELY(domain < 0))
1270      {
1271         if (file && fnc && fmt)
1272            fprintf(
1273               stderr,
1274               "CRI: %s:%d %s() eina_log_print() unknown domain %d, original message format '%s'\n",
1275               file,
1276               line,
1277               fnc,
1278               domain,
1279               fmt);
1280         else
1281            fprintf(
1282               stderr,
1283               "CRI: eina_log_print() unknown domain %d, original message format '%s'\n",
1284               domain,
1285               fmt ? fmt : "");
1286
1287         if (_abort_on_critical)
1288            abort();
1289
1290         return;
1291      }
1292
1293 #endif
1294    d = _log_domains + domain;
1295 #ifdef EINA_SAFETY_CHECKS
1296    if (EINA_UNLIKELY(d->deleted))
1297      {
1298            fprintf(stderr,
1299                 "ERR: eina_log_print() domain %d is deleted\n",
1300                 domain);
1301         return;
1302      }
1303
1304 #endif
1305
1306    if (level > d->level)
1307       return;
1308
1309 #ifdef _WIN32
1310    {
1311       char *wfmt;
1312       char *tmp;
1313
1314       wfmt = strdup(fmt);
1315       if (!wfmt)
1316         {
1317            fprintf(stderr, "ERR: %s: can not allocate memory\n", __FUNCTION__);
1318            return;
1319         }
1320
1321       tmp = wfmt;
1322       while (strchr(tmp, '%'))
1323         {
1324            tmp++;
1325            if (*tmp == 'z')
1326               *tmp = 'I';
1327         }
1328       _print_cb(d, level, file, fnc, line, wfmt, _print_cb_data, args);
1329       free(wfmt);
1330    }
1331 #else
1332    _print_cb(d, level, file, fnc, line, fmt, _print_cb_data, args);
1333 #endif
1334
1335    if (EINA_UNLIKELY(_abort_on_critical) &&
1336        EINA_UNLIKELY(level <= _abort_level_on_critical))
1337       abort();
1338 }
1339
1340 #endif
1341
1342 /**
1343  * @endcond
1344  */
1345
1346
1347 /*============================================================================*
1348 *                                 Global                                     *
1349 *============================================================================*/
1350
1351 /**
1352  * @internal
1353  * @brief Initialize the log module.
1354  *
1355  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
1356  *
1357  * This function sets up the log module of Eina. It is called by
1358  * eina_init().
1359  *
1360  * @see eina_init()
1361  *
1362  * @warning Not-MT: just call this function from main thread! The
1363  *          place where this function was called the first time is
1364  *          considered the main thread.
1365  */
1366 Eina_Bool
1367 eina_log_init(void)
1368 {
1369 #ifdef EINA_ENABLE_LOG
1370    const char *level, *tmp;
1371    int color_disable;
1372
1373    assert((sizeof(_names) / sizeof(_names[0])) == EINA_LOG_LEVELS);
1374
1375 #ifdef EINA_LOG_BACKTRACE
1376    if ((tmp = getenv(EINA_LOG_ENV_BACKTRACE)))
1377      _backtrace_level = atoi(tmp);
1378 #endif
1379
1380    if ((tmp = getenv(EINA_LOG_ENV_COLOR_DISABLE)))
1381       color_disable = atoi(tmp);
1382    else
1383       color_disable = -1;
1384
1385    /* Check if color is explicitly disabled */
1386    if (color_disable == 1)
1387       _disable_color = EINA_TRUE;
1388
1389 #ifndef _WIN32
1390    /* color was not explicitly disabled or enabled, guess it */
1391    else if (color_disable == -1)
1392      {
1393         if (!eina_log_term_color_supported(getenv("TERM")))
1394            _disable_color = EINA_TRUE;
1395         else
1396           {
1397              /* if not a terminal, but redirected to a file, disable color */
1398              int fd;
1399
1400              if (_print_cb == eina_log_print_cb_stderr)
1401                 fd = STDERR_FILENO;
1402              else if (_print_cb == eina_log_print_cb_stdout)
1403                 fd = STDOUT_FILENO;
1404              else
1405                 fd = -1;
1406
1407              if ((fd >= 0) && (!isatty(fd)))
1408                 _disable_color = EINA_TRUE;
1409           }
1410      }
1411 #endif
1412
1413    if ((tmp = getenv(EINA_LOG_ENV_FILE_DISABLE)) && (atoi(tmp) == 1))
1414       _disable_file = EINA_TRUE;
1415
1416    if ((tmp = getenv(EINA_LOG_ENV_FUNCTION_DISABLE)) && (atoi(tmp) == 1))
1417       _disable_function = EINA_TRUE;
1418
1419    if ((tmp = getenv(EINA_LOG_ENV_ABORT)) && (atoi(tmp) == 1))
1420       _abort_on_critical = EINA_TRUE;
1421
1422    if ((tmp = getenv(EINA_LOG_ENV_ABORT_LEVEL)))
1423       _abort_level_on_critical = atoi(tmp);
1424
1425    eina_log_print_prefix_update();
1426
1427    // Global log level
1428    if ((level = getenv(EINA_LOG_ENV_LEVEL)))
1429       _log_level = atoi(level);
1430
1431    // Register UNKNOWN domain, the default logger
1432    EINA_LOG_DOMAIN_GLOBAL = eina_log_domain_register("", NULL);
1433
1434    if (EINA_LOG_DOMAIN_GLOBAL < 0)
1435      {
1436         fprintf(stderr, "Failed to create global logging domain.\n");
1437         return EINA_FALSE;
1438      }
1439
1440    // Parse pending domains passed through EINA_LOG_LEVELS_GLOB
1441    eina_log_domain_parse_pending_globs();
1442
1443    // Parse pending domains passed through EINA_LOG_LEVELS
1444    eina_log_domain_parse_pendings();
1445
1446 #endif
1447    return EINA_TRUE;
1448 }
1449
1450 /**
1451  * @internal
1452  * @brief Shut down the log module.
1453  *
1454  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
1455  *
1456  * This function shuts down the log module set up by
1457  * eina_log_init(). It is called by eina_shutdown().
1458  *
1459  * @see eina_shutdown()
1460  *
1461  * @warning Not-MT: just call this function from main thread! The
1462  *          place where eina_log_init() (eina_init()) was called the
1463  *          first time is considered the main thread.
1464  */
1465 Eina_Bool
1466 eina_log_shutdown(void)
1467 {
1468 #ifdef EINA_ENABLE_LOG
1469    Eina_Inlist *tmp;
1470
1471    while (_log_domains_count--)
1472      {
1473         if (_log_domains[_log_domains_count].deleted)
1474            continue;
1475
1476         eina_log_domain_free(&_log_domains[_log_domains_count]);
1477      }
1478
1479         free(_log_domains);
1480
1481    _log_domains = NULL;
1482    _log_domains_count = 0;
1483    _log_domains_allocated = 0;
1484
1485    while (_glob_list)
1486      {
1487         tmp = _glob_list;
1488         _glob_list = _glob_list->next;
1489         free(tmp);
1490      }
1491
1492    while (_pending_list)
1493      {
1494         tmp = _pending_list;
1495         _pending_list = _pending_list->next;
1496         free(tmp);
1497      }
1498
1499 #endif
1500    return EINA_TRUE;
1501 }
1502
1503 #ifdef EFL_HAVE_THREADS
1504
1505 /**
1506  * @internal
1507  * @brief Activate the log mutex.
1508  *
1509  * This function activate the mutex in the eina log module. It is called by
1510  * eina_threads_init().
1511  *
1512  * @see eina_threads_init()
1513  */
1514 void
1515 eina_log_threads_init(void)
1516 {
1517 #ifdef EINA_ENABLE_LOG
1518    if (_threads_inited) return;
1519    _main_thread = SELF();
1520    if (!INIT()) return;
1521    _threads_inited = EINA_TRUE;
1522 #endif
1523 }
1524
1525 /**
1526  * @internal
1527  * @brief Shut down the log mutex.
1528  *
1529  * This function shuts down the mutex in the log module.
1530  * It is called by eina_threads_shutdown().
1531  *
1532  * @see eina_threads_shutdown()
1533  */
1534 void
1535 eina_log_threads_shutdown(void)
1536 {
1537 #ifdef EINA_ENABLE_LOG
1538    if (!_threads_inited) return;
1539    CHECK_MAIN();
1540    SHUTDOWN();
1541    _threads_enabled = EINA_FALSE;
1542    _threads_inited = EINA_FALSE;
1543 #endif
1544 }
1545
1546 #endif
1547
1548 /*============================================================================*
1549 *                                   API                                      *
1550 *============================================================================*/
1551
1552 /**
1553  * @cond LOCAL
1554  */
1555
1556 EAPI int EINA_LOG_DOMAIN_GLOBAL = 0;
1557
1558 /**
1559  * @endcond
1560  */
1561
1562 EAPI void
1563 eina_log_threads_enable(void)
1564 {
1565 #if defined (EFL_HAVE_THREADS) && defined (EINA_ENABLE_LOG)
1566    if (_threads_enabled) return;
1567    if (!_threads_inited) eina_log_threads_init();
1568    _threads_enabled = EINA_TRUE;
1569    eina_log_print_prefix_update();
1570 #endif
1571 }
1572
1573 EAPI void
1574 eina_log_print_cb_set(Eina_Log_Print_Cb cb, void *data)
1575 {
1576 #ifdef EINA_ENABLE_LOG
1577    LOG_LOCK();
1578    _print_cb = cb;
1579    _print_cb_data = data;
1580    eina_log_print_prefix_update();
1581    LOG_UNLOCK();
1582 #else
1583    (void) cb;
1584    (void) data;
1585 #endif
1586 }
1587
1588 EAPI void
1589 eina_log_level_set(int level)
1590 {
1591 #ifdef EINA_ENABLE_LOG
1592    _log_level = level;
1593    if (EINA_LIKELY((EINA_LOG_DOMAIN_GLOBAL >= 0) &&
1594                    ((unsigned int)EINA_LOG_DOMAIN_GLOBAL < _log_domains_count)))
1595       _log_domains[EINA_LOG_DOMAIN_GLOBAL].level = level;
1596 #else
1597    (void) level;
1598 #endif
1599 }
1600
1601 EAPI int
1602 eina_log_level_get(void)
1603 {
1604 #ifdef EINA_ENABLE_LOG
1605    return _log_level;
1606 #else
1607    return 0;
1608 #endif
1609 }
1610
1611 EAPI Eina_Bool
1612 eina_log_main_thread_check(void)
1613 {
1614 #if defined (EFL_HAVE_THREADS) && defined (EINA_ENABLE_LOG)
1615    return ((!_threads_enabled) || IS_MAIN(SELF()));
1616 #else
1617    return EINA_TRUE;
1618 #endif
1619 }
1620
1621 EAPI void
1622 eina_log_color_disable_set(Eina_Bool disabled)
1623 {
1624 #ifdef EINA_ENABLE_LOG
1625    _disable_color = disabled;
1626 #else
1627    (void) disabled;
1628 #endif
1629 }
1630
1631 EAPI Eina_Bool
1632 eina_log_color_disable_get(void)
1633 {
1634 #ifdef EINA_ENABLE_LOG
1635    return _disable_color;
1636 #else
1637    return EINA_TRUE;
1638 #endif
1639 }
1640
1641 EAPI void
1642 eina_log_file_disable_set(Eina_Bool disabled)
1643 {
1644 #ifdef EINA_ENABLE_LOG
1645    _disable_file = disabled;
1646 #else
1647    (void) disabled;
1648 #endif
1649 }
1650
1651 EAPI Eina_Bool
1652 eina_log_file_disable_get(void)
1653 {
1654 #ifdef EINA_ENABLE_LOG
1655    return _disable_file;
1656 #else
1657    return EINA_TRUE;
1658 #endif
1659 }
1660
1661 EAPI void
1662 eina_log_function_disable_set(Eina_Bool disabled)
1663 {
1664 #ifdef EINA_ENABLE_LOG
1665    _disable_function = disabled;
1666 #else
1667    (void) disabled;
1668 #endif
1669 }
1670
1671 EAPI Eina_Bool
1672 eina_log_function_disable_get(void)
1673 {
1674 #ifdef EINA_ENABLE_LOG
1675    return _disable_function;
1676 #else
1677    return EINA_TRUE;
1678 #endif
1679 }
1680
1681 EAPI void
1682 eina_log_abort_on_critical_set(Eina_Bool abort_on_critical)
1683 {
1684 #ifdef EINA_ENABLE_LOG
1685    _abort_on_critical = abort_on_critical;
1686 #else
1687    (void) abort_on_critical;
1688 #endif
1689 }
1690
1691 EAPI Eina_Bool
1692 eina_log_abort_on_critical_get(void)
1693 {
1694 #ifdef EINA_ENABLE_LOG
1695    return _abort_on_critical;
1696 #else
1697    return EINA_FALSE;
1698 #endif
1699 }
1700
1701 EAPI void
1702 eina_log_abort_on_critical_level_set(int critical_level)
1703 {
1704 #ifdef EINA_ENABLE_LOG
1705    _abort_level_on_critical = critical_level;
1706 #else
1707    (void) critical_level;
1708 #endif
1709 }
1710
1711 EAPI int
1712 eina_log_abort_on_critical_level_get(void)
1713 {
1714 #ifdef EINA_ENABLE_LOG
1715    return _abort_level_on_critical;
1716 #else
1717    return 0;
1718 #endif
1719 }
1720
1721 EAPI int
1722 eina_log_domain_register(const char *name, const char *color)
1723 {
1724 #ifdef EINA_ENABLE_LOG
1725    int r;
1726
1727    EINA_SAFETY_ON_NULL_RETURN_VAL(name, -1);
1728
1729    LOG_LOCK();
1730    r = eina_log_domain_register_unlocked(name, color);
1731    LOG_UNLOCK();
1732    return r;
1733 #else
1734    (void) name;
1735    (void) color;
1736    return 0;
1737 #endif
1738 }
1739
1740 EAPI void
1741 eina_log_domain_unregister(int domain)
1742 {
1743 #ifdef EINA_ENABLE_LOG
1744    EINA_SAFETY_ON_FALSE_RETURN(domain >= 0);
1745    LOG_LOCK();
1746    eina_log_domain_unregister_unlocked(domain);
1747    LOG_UNLOCK();
1748 #else
1749    (void) domain;
1750 #endif
1751 }
1752
1753 EAPI void
1754 eina_log_domain_level_set(const char *domain_name, int level)
1755 {
1756 #ifdef EINA_ENABLE_LOG
1757    Eina_Log_Domain_Level_Pending *pending;
1758    size_t namelen;
1759    unsigned int i;
1760
1761    EINA_SAFETY_ON_NULL_RETURN(domain_name);
1762
1763    namelen = strlen(domain_name);
1764
1765    for (i = 0; i < _log_domains_count; i++)
1766      {
1767         if (_log_domains[i].deleted)
1768            continue;
1769
1770         if ((namelen != _log_domains[i].namelen) ||
1771             (strcmp(_log_domains[i].name, domain_name) != 0))
1772            continue;
1773
1774         _log_domains[i].level = level;
1775         return;
1776      }
1777
1778    EINA_INLIST_FOREACH(_pending_list, pending)
1779    {
1780       if ((namelen == pending->namelen) &&
1781           (strcmp(pending->name, domain_name) == 0))
1782         {
1783            pending->level = level;
1784            return;
1785         }
1786    }
1787
1788    pending = malloc(sizeof(Eina_Log_Domain_Level_Pending) + namelen + 1);
1789    if (!pending)
1790       return;
1791
1792    pending->level = level;
1793    pending->namelen = namelen;
1794    memcpy(pending->name, domain_name, namelen + 1);
1795
1796    _pending_list = eina_inlist_append(_pending_list, EINA_INLIST_GET(pending));
1797 #else
1798    (void) domain_name;
1799    (void) level;
1800 #endif
1801 }
1802
1803 EAPI int
1804 eina_log_domain_level_get(const char *domain_name)
1805 {
1806 #ifdef EINA_ENABLE_LOG
1807    Eina_Log_Domain_Level_Pending *pending;
1808    size_t namelen;
1809    unsigned int i;
1810
1811    EINA_SAFETY_ON_NULL_RETURN_VAL(domain_name, EINA_LOG_LEVEL_UNKNOWN);
1812
1813    namelen = strlen(domain_name);
1814
1815    for (i = 0; i < _log_domains_count; i++)
1816      {
1817         if (_log_domains[i].deleted)
1818            continue;
1819
1820         if ((namelen != _log_domains[i].namelen) ||
1821             (strcmp(_log_domains[i].name, domain_name) != 0))
1822            continue;
1823
1824         return _log_domains[i].level;
1825      }
1826
1827    EINA_INLIST_FOREACH(_pending_list, pending)
1828    {
1829       if ((namelen == pending->namelen) &&
1830           (strcmp(pending->name, domain_name) == 0))
1831          return pending->level;
1832    }
1833
1834    EINA_INLIST_FOREACH(_glob_list, pending)
1835    {
1836       if (!fnmatch(pending->name, domain_name, 0))
1837          return pending->level;
1838    }
1839
1840    return _log_level;
1841 #else
1842    (void) domain_name;
1843    return 0;
1844 #endif
1845 }
1846
1847 EAPI int
1848 eina_log_domain_registered_level_get(int domain)
1849 {
1850 #ifdef EINA_ENABLE_LOG
1851    EINA_SAFETY_ON_FALSE_RETURN_VAL(domain >= 0, EINA_LOG_LEVEL_UNKNOWN);
1852    EINA_SAFETY_ON_FALSE_RETURN_VAL((unsigned int)domain < _log_domains_count,
1853                                    EINA_LOG_LEVEL_UNKNOWN);
1854    EINA_SAFETY_ON_TRUE_RETURN_VAL(_log_domains[domain].deleted,
1855                                   EINA_LOG_LEVEL_UNKNOWN);
1856    return _log_domains[domain].level;
1857 #else
1858    (void) domain;
1859    return 0;
1860 #endif
1861 }
1862
1863 #ifdef EINA_LOG_BACKTRACE
1864 # define DISPLAY_BACKTRACE(File, Level)                 \
1865   if (EINA_UNLIKELY(Level < _backtrace_level))          \
1866     {                                                   \
1867       void *bt[256];                                    \
1868       char **strings;                                   \
1869       int btlen;                                        \
1870       int i;                                            \
1871                                                         \
1872       btlen = backtrace((void **)bt, 256);              \
1873       strings = backtrace_symbols((void **)bt, btlen);  \
1874       fprintf(File, "*** Backtrace ***\n");             \
1875       for (i = 0; i < btlen; ++i)                       \
1876         fprintf(File, "%s\n", strings[i]);              \
1877       free(strings);                                    \
1878     }
1879 #else
1880 # define DISPLAY_BACKTRACE(File, Level)
1881 #endif
1882
1883 EAPI void
1884 eina_log_print_cb_stderr(const Eina_Log_Domain *d,
1885                          Eina_Log_Level level,
1886                          const char *file,
1887                          const char *fnc,
1888                          int line,
1889                          const char *fmt,
1890                          __UNUSED__ void *data,
1891                          va_list args)
1892 {
1893 #ifdef EINA_ENABLE_LOG
1894    _eina_log_print_prefix(stderr, d, level, file, fnc, line);
1895    vfprintf(stderr, fmt, args);
1896    putc('\n', stderr);
1897    DISPLAY_BACKTRACE(stderr, level);
1898 #else
1899    (void) d;
1900    (void) level;
1901    (void) file;
1902    (void) fnc;
1903    (void) line;
1904    (void) fmt;
1905    (void) data;
1906    (void) args;
1907 #endif
1908 }
1909
1910 EAPI void
1911 eina_log_print_cb_stdout(const Eina_Log_Domain *d,
1912                          Eina_Log_Level level,
1913                          const char *file,
1914                          const char *fnc,
1915                          int line,
1916                          const char *fmt,
1917                          __UNUSED__ void *data,
1918                          va_list args)
1919 {
1920 #ifdef EINA_ENABLE_LOG
1921    _eina_log_print_prefix(stdout, d, level, file, fnc, line);
1922    vprintf(fmt, args);
1923    putchar('\n');
1924    DISPLAY_BACKTRACE(stdout, level);
1925 #else
1926    (void) d;
1927    (void) level;
1928    (void) file;
1929    (void) fnc;
1930    (void) line;
1931    (void) fmt;
1932    (void) data;
1933    (void) args;
1934 #endif
1935 }
1936
1937 EAPI void
1938 eina_log_print_cb_file(const Eina_Log_Domain *d,
1939                        __UNUSED__ Eina_Log_Level level,
1940                        const char *file,
1941                        const char *fnc,
1942                        int line,
1943                        const char *fmt,
1944                        void *data,
1945                        va_list args)
1946 {
1947 #ifdef EINA_ENABLE_LOG
1948    FILE *f = data;
1949 #ifdef EFL_HAVE_THREADS
1950    if (_threads_enabled)
1951      {
1952         Thread cur;
1953
1954         cur = SELF();
1955         if (IS_OTHER(cur))
1956           {
1957              fprintf(f, "%s[T:%lu] %s:%d %s() ", d->name, (unsigned long)cur,
1958                 file, line, fnc);
1959              goto end;
1960           }
1961      }
1962
1963 #endif
1964    fprintf(f, "%s<%u> %s:%d %s() ", d->name, eina_log_pid_get(), 
1965            file, line, fnc);
1966    DISPLAY_BACKTRACE(f, level);
1967 #ifdef EFL_HAVE_THREADS
1968 end:
1969 #endif
1970    vfprintf(f, fmt, args);
1971    putc('\n', f);
1972 #else
1973    (void) d;
1974    (void) file;
1975    (void) fnc;
1976    (void) line;
1977    (void) fmt;
1978    (void) data;
1979    (void) args;
1980 #endif
1981 }
1982
1983 EAPI void
1984 eina_log_print(int domain, Eina_Log_Level level, const char *file,
1985                const char *fnc, int line, const char *fmt, ...)
1986 {
1987 #ifdef EINA_ENABLE_LOG
1988    va_list args;
1989
1990 #ifdef EINA_SAFETY_CHECKS
1991    if (EINA_UNLIKELY(!file))
1992      {
1993         fputs("ERR: eina_log_print() file == NULL\n", stderr);
1994         return;
1995      }
1996
1997    if (EINA_UNLIKELY(!fnc))
1998      {
1999         fputs("ERR: eina_log_print() fnc == NULL\n", stderr);
2000         return;
2001      }
2002
2003    if (EINA_UNLIKELY(!fmt))
2004      {
2005         fputs("ERR: eina_log_print() fmt == NULL\n", stderr);
2006         return;
2007      }
2008
2009 #endif
2010    va_start(args, fmt);
2011    LOG_LOCK();
2012    eina_log_print_unlocked(domain, level, file, fnc, line, fmt, args);
2013    LOG_UNLOCK();
2014    va_end(args);
2015 #else
2016    (void) domain;
2017    (void) level;
2018    (void) file;
2019    (void) fnc;
2020    (void) line;
2021    (void) fmt;
2022 #endif
2023 }
2024
2025 EAPI void
2026 eina_log_vprint(int domain, Eina_Log_Level level, const char *file,
2027                 const char *fnc, int line, const char *fmt, va_list args)
2028 {
2029 #ifdef EINA_ENABLE_LOG
2030
2031 #ifdef EINA_SAFETY_CHECKS
2032    if (EINA_UNLIKELY(!file))
2033      {
2034         fputs("ERR: eina_log_print() file == NULL\n", stderr);
2035         return;
2036      }
2037
2038    if (EINA_UNLIKELY(!fnc))
2039      {
2040         fputs("ERR: eina_log_print() fnc == NULL\n", stderr);
2041         return;
2042      }
2043
2044    if (EINA_UNLIKELY(!fmt))
2045      {
2046         fputs("ERR: eina_log_print() fmt == NULL\n", stderr);
2047         return;
2048      }
2049
2050 #endif
2051    LOG_LOCK();
2052    eina_log_print_unlocked(domain, level, file, fnc, line, fmt, args);
2053    LOG_UNLOCK();
2054 #else
2055    (void) domain;
2056    (void) level;
2057    (void) file;
2058    (void) fnc;
2059    (void) line;
2060    (void) fmt;
2061    (void) args;
2062 #endif
2063 }
2064
2065 EAPI void
2066 eina_log_console_color_set(FILE *fp, const char *color)
2067 {
2068 #ifdef EINA_ENABLE_LOG
2069
2070    EINA_SAFETY_ON_NULL_RETURN(fp);
2071    EINA_SAFETY_ON_NULL_RETURN(color);
2072    if (_disable_color) return;
2073
2074 #ifdef _WIN32
2075    int attr = eina_log_win32_color_convert(color, NULL);
2076    HANDLE *handle;
2077
2078    if (!attr) return;
2079
2080    if (fp == stderr)
2081      handle = GetStdHandle(STD_ERROR_HANDLE);
2082    else if (fp == stdout)
2083      handle = GetStdHandle(STD_OUTPUT_HANDLE);
2084    else
2085      {
2086         /* Do we have a way to convert FILE* to HANDLE?
2087          * Should we use it?
2088          */
2089         return;
2090      }
2091    SetConsoleTextAttribute(handle, attr);
2092 #else
2093    fputs(color, fp);
2094 #endif
2095
2096 #else
2097    (void)color;
2098 #endif
2099 }