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