Newer version: fix EINA_ERROR_LEVELS parsing issue.
On Sat, Jul 25, 2009 at 10:44 PM, Andre Dieb
<andre.mart...@ee.ufcg.edu.br>wrote:
> Removing workaround with unused variable..
>
>
> On Sat, Jul 25, 2009 at 10:30 PM, Andre Dieb <andre.mart...@ee.ufcg.edu.br
> > wrote:
>
>> Fix a missing free() spotted by Sachiel.
>>
>>
>> On Sat, Jul 25, 2009 at 9:21 PM, Andre Dieb <andre.mart...@ee.ufcg.edu.br
>> > wrote:
>>
>>> The new patch is attached (hope it works now).
>>>
>>>
>>> On Sat, Jul 25, 2009 at 9:04 PM, Andre Dieb <
>>> andre.mart...@ee.ufcg.edu.br> wrote:
>>>
>>>> The new patch is attached.
>>>>
>>>> On Sat, Jul 18, 2009 at 1:57 PM, Gustavo Sverzut Barbieri
>>>> <barbi...@profusion.mobi> wrote:
>>>>
>>>>> On Fri, Jul 17, 2009 at 6:55 PM, Andre Dieb<
>>>>> andre.mart...@ee.ufcg.edu.br> wrote:
>>>>> > Hello,
>>>>> >
>>>>> > This patch contains an initial implementation of logging domains for
>>>>> eina
>>>>> > error module. Please be aware that this a very rough version and
>>>>> there are
>>>>> > lots of things that must be improved.
>>>>> >
>>>>> > The patch is also with lots of fprintf's that I was using for
>>>>> debugging,
>>>>> > please ignore them. When we're ready to apply, I'll cleanup
>>>>> everything.
>>>>> >
>>>>> > For testing the new domain features, I added three unit tests and
>>>>> fixed
>>>>> > eina_rectangle test that was preventing me from building eina_error
>>>>> test.
>>>>> > You can also see examples of how logging domains will be used on
>>>>> these tests
>>>>> > (registering, logging, unregistering).
>>>>>
>>>>> Okay, couple of issues. One of them was already spotted by Sachiel,
>>>>> but other follows:
>>>>>
>>>>> Header:
>>>>>
>>>>> +typedef int Eina_Error_Domain_Index;
>>>>>
>>>>> this typedef is a bit too much.
>>>>>
>>>>> +struct _Eina_Error_Domain
>>>>> +{
>>>>> + EINA_INLIST;
>>>>>
>>>>> ouch, this is legacy and not being used! Remove it.
>>>>>
>>>>> + unsigned int level; /**< Max level to log */
>>>>> + const char *name; /**< Domain name */
>>>>> + const char *domain_str; /**< Formatted string with color to print
>>>>> */
>>>>> + const char *color;
>>>>> +
>>>>> + /* Private */
>>>>> + int deleted : 1; /**< Flags deletion of domain, a free slot */
>>>>>
>>>>> Eina_Bool, otherwise deleted is just the sign bit and deleted is (-1,
>>>>> 0), not (1, 0)
>>>>>
>>>>>
>>>>> +typedef struct _Eina_Error_Domain_Level_Pending
>>>>> Eina_Error_Domain_Level_Pending
>>>>> +struct _Eina_Error_Domain_Level_Pending
>>>>>
>>>>> These are private to eina_error.c
>>>>>
>>>>> +struct _Eina_Error_Domain_Level_Pending
>>>>> +{
>>>>> + EINA_INLIST;
>>>>> +
>>>>> + const char *name;
>>>>> + unsigned int level;
>>>>> +};
>>>>>
>>>>> change to the following and get the pointer arithmetic for free, also
>>>>> saving one pointer access and sizeof(char*) bytes.:
>>>>> +struct _Eina_Error_Domain_Level_Pending
>>>>> +{
>>>>> + EINA_INLIST;
>>>>> +
>>>>> + unsigned int level;
>>>>> char name[];
>>>>> +};
>>>>>
>>>>> +typedef void (*Eina_Error_Dom_Print_Cb)(Eina_Error_Domain_Index i,
>>>>> Eina_Error_Level level, const char *file,
>>>>> + const char *fnc, int line, const char *fmt, void
>>>>> *data,
>>>>> + va_list args);
>>>>> +
>>>>>
>>>>> and all other callbacks: domain index is useless, you should give it
>>>>> the pointer to domain! Imagine I want to implement my own logging in
>>>>> my program, how could I access the log domain? Other than that, domain
>>>>> index is pretty much useless.
>>>>>
>>>>>
>>>>> Code:
>>>>>
>>>>> +static Eina_Error_Domain **_error_domains = NULL;
>>>>>
>>>>> Sachiel spotted you're misusing the _error_domains by allocating
>>>>> sizeof(Eina_Error_Domain) instead of pointer. But I guess this should
>>>>> be really an array of domains and not an array of pointers. So just
>>>>> change that to Eina_Error_Domain *_error_domains. That's why you need
>>>>> "domain->deleted", otherwise just free and set to NULL. The other
>>>>> option is to remove "deleted" and keep this as a pointer, but I guess
>>>>> it's marginally worse.
>>>>>
>>>>> +static int _error_domains_count = 0;
>>>>>
>>>>> see eina_array, you need 2 counters, one for current size (count) and
>>>>> another for allocated size. Then you do not need to memset()/NULL-ify
>>>>> remaining slots. If you want to avoid useless walks in this array, you
>>>>> can keep an extra "free" count, that would say the number of free
>>>>> slots inside _error_domains_count. It would increase when you remove
>>>>> elements before last. If you remove last, just decrease
>>>>> error_domains_count. If want to bit super-correct, when you remove
>>>>> last you'd walk backwards checking for already freed slots and move
>>>>> that amount from _free to _count. Ie:
>>>>>
>>>>> [xxxxx###], count=5, size=8, free=0
>>>>> [xxx#x###], count=5, size=8, free=1
>>>>> [xxx#####], count=3, size=8, free=0
>>>>>
>>>>>
>>>>> +static int _pending_list_count = 0;
>>>>>
>>>>> remove, this is useless.
>>>>>
>>>>>
>>>>> + d = malloc(sizeof(char) * (color_len + name_len +
>>>>> strlen(EINA_COLOR_WHITE) + 1));
>>>>>
>>>>> oops, don't assume everybody uses dark terminals! You should use
>>>>> EINA_COLOR_NOTHING. And while compiler should optimize strlen() for
>>>>> that string, you can remove that with sizeof(), and it already
>>>>> accounts trailing \0. Same for memcpy(), just give it sizeof() and it
>>>>> will copy the null terminator.
>>>>>
>>>>> + d->color = malloc(sizeof(char)*(strlen(color)+1));
>>>>> + memcpy((char *)d->color, color, strlen(color));
>>>>>
>>>>> you can just strdup() here. And while most compilers would optimize
>>>>> strlen(), keeping a variable with that value would make your code
>>>>> easier to read.
>>>>>
>>>>> if you allocate all the strings in a single memory blob, it's even
>>>>> better.
>>>>>
>>>>>
>>>>> +static void
>>>>> +eina_error_domain_free(Eina_Error_Domain *d)
>>>>> +{
>>>>> + if (!d) return;
>>>>> +
>>>>> + if (d->name)
>>>>> + free((char *)d->name);
>>>>> + if (d->domain_str)
>>>>> + free((char *)d->domain_str);
>>>>> +
>>>>> + free(d);
>>>>> +}
>>>>>
>>>>> how about color? that's the benefit of using a single blob, just free
>>>>> the pointer that is the head, everything else goes aways
>>>>> automatically.
>>>>>
>>>>> + // Form name:level,name1:level1,name2:level2,...
>>>>> ...
>>>>> + p->level = strtol((char *)(end + 1), &tmp, 10);
>>>>> ...
>>>>> + start = tmp + 1;
>>>>>
>>>>> doc fail! :-) You need to strchr(tmp, ',') to find out next comma.
>>>>> Also add that doc (and other env vars!) to header.
>>>>>
>>>>> + EINA_ERROR_DOMAIN_GLOBAL = eina_error_domain_register(NULL,
>>>>> NULL);
>>>>> i guess it would be better to give real values to this function and
>>>>> actually make it complain on NULL pointers, also adding
>>>>> EINA_ARG_NONNULL() to header signature.
>>>>>
>>>>>
>>>>> + // Check if color is disabled
>>>>> + if ((tmp = getenv("EINA_ERROR_COLOR_DISABLE")))
>>>>> + if (atoi(tmp) == 1) _disable_color = 1;
>>>>> do this before everything else, so functions that check for
>>>>> _disable_color will always consider it correctly.
>>>>>
>>>>> +finish_register:
>>>>> + EINA_INLIST_FOREACH(_pending_list, pending)
>>>>> + {
>>>>> + if (!strcmp(pending->name, name))
>>>>> + {
>>>>> + fprintf(stderr, "Updating domain %s level from %d to
>>>>> %d\n",
>>>>> name, _error_domains[i]->level, pending->level);
>>>>> + _error_domains[i]->level = pending->level;
>>>>> + _pending_list = eina_inlist_remove(_pending_list,
>>>>> EINA_INLIST_GET(pending));
>>>>> + break;
>>>>> + }
>>>>> + }
>>>>>
>>>>> oops, leaked pending!
>>>>>
>>>>>
>>>>> +eina_error_dom_print_cb_stdout(Eina_Error_Domain_Index i,
>>>>> Eina_Error_Level level,
>>>>> + const char *file, const char *fnc, int line, const char
>>>>> *fmt,
>>>>> + __UNUSED__ void *data, va_list args)
>>>>> +{
>>>>> + Eina_Error_Domain *d;
>>>>> + d = _error_domains[i];
>>>>> +
>>>>> + if (!d) return;
>>>>> +
>>>>> + printf("%s\t%s%s:%d %s()%s ", (d->domain_str) ? d->domain_str :
>>>>> ((d->name) ? d->name : ""),
>>>>> + (!_disable_color) ? _colors[level] :
>>>>> "",
>>>>> + file, line, fnc,
>>>>> + (!_disable_color) ?
>>>>> _colors[EINA_ERROR_LEVEL_INFO] : "");
>>>>> + vprintf(fmt, args);
>>>>> +}
>>>>>
>>>>> just guarantee these strings will always be valid. And give this
>>>>> callback a const Eina_Error_Domain. The point of having domain_str and
>>>>> name is to avoid doing these checks during every print.
>>>>>
>>>>> +
>>>>> + if (getenv("EINA_ERROR_ABORT")) abort();
>>>>> +}
>>>>>
>>>>> this is bad and would make abort on any debug if its level is visible.
>>>>> Just check if level is greater than error/critical/whatever.
>>>>>
>>>>> All in all it looks good, just fix these points and I'll commit.
>>>>>
>>>>> --
>>>>> Gustavo Sverzut Barbieri
>>>>> http://profusion.mobi embedded systems
>>>>> --------------------------------------
>>>>> MSN: barbi...@gmail.com
>>>>> Skype: gsbarbieri
>>>>> Mobile: +55 (19) 9225-2202
>>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> André Dieb Martins
>>>>
>>>> Embedded Systems and Pervasive Computing Lab (Embedded)
>>>> Electrical Engineering Department (DEE)
>>>> Center of Electrical Engineering and Informatics (CEEI)
>>>> Federal University of Campina Grande (UFCG)
>>>>
>>>> Blog: http://genuinepulse.blogspot.com/
>>>>
>>>
>>>
>>>
>>> --
>>> André Dieb Martins
>>>
>>> Embedded Systems and Pervasive Computing Lab (Embedded)
>>> Electrical Engineering Department (DEE)
>>> Center of Electrical Engineering and Informatics (CEEI)
>>> Federal University of Campina Grande (UFCG)
>>>
>>> Blog: http://genuinepulse.blogspot.com/
>>>
>>
>>
>>
>> --
>> André Dieb Martins
>>
>> Embedded Systems and Pervasive Computing Lab (Embedded)
>> Electrical Engineering Department (DEE)
>> Center of Electrical Engineering and Informatics (CEEI)
>> Federal University of Campina Grande (UFCG)
>>
>> Blog: http://genuinepulse.blogspot.com/
>>
>
>
>
> --
> André Dieb Martins
>
> Embedded Systems and Pervasive Computing Lab (Embedded)
> Electrical Engineering Department (DEE)
> Center of Electrical Engineering and Informatics (CEEI)
> Federal University of Campina Grande (UFCG)
>
> Blog: http://genuinepulse.blogspot.com/
>
--
André Dieb Martins
Embedded Systems and Pervasive Computing Lab (Embedded)
Electrical Engineering Department (DEE)
Center of Electrical Engineering and Informatics (CEEI)
Federal University of Campina Grande (UFCG)
Blog: http://genuinepulse.blogspot.com/
Index: src/tests/eina_test_error.c
===================================================================
--- src/tests/eina_test_error.c (revision 41496)
+++ src/tests/eina_test_error.c (working copy)
@@ -29,14 +29,17 @@
START_TEST(eina_error_init_shutdown)
{
- eina_error_init();
- eina_error_init();
- eina_error_shutdown();
- eina_error_init();
- eina_error_init();
- eina_error_shutdown();
- eina_error_shutdown();
- eina_error_shutdown();
+ int initial_level = eina_error_init() - 1;
+ fail_if(!initial_level);
+
+ fail_if(!eina_error_init());
+ fail_if(!eina_error_shutdown());
+ fail_if(!eina_error_init());
+ fail_if(!eina_error_init());
+ fail_if(!eina_error_shutdown());
+ fail_if(!eina_error_shutdown());
+
+ fail_if(initial_level != eina_error_shutdown());
}
END_TEST
@@ -48,7 +51,7 @@
setenv("EINA_ERROR_LEVEL", "1", 0);
- eina_error_init();
+ fail_if(!eina_error_init());
test = eina_error_msg_register(TEST_TEXT);
fail_if(!eina_error_msg_get(test));
@@ -63,7 +66,7 @@
START_TEST(eina_error_macro)
{
- eina_error_init();
+ fail_if(!eina_error_init());
eina_error_log_level_set(EINA_ERROR_LEVEL_DBG);
eina_error_print_cb_set(eina_error_print_cb_file, stderr);
@@ -77,10 +80,85 @@
}
END_TEST
+START_TEST(eina_error_domains_macros)
+{
+ fail_if(!eina_error_init());
+
+ int d = eina_error_domain_register("MyDomain", EINA_COLOR_GREEN);
+ fail_if(d < 0);
+
+ EINA_ERROR_PERR_DOM(d, "An error\n");
+ EINA_ERROR_PINFO_DOM(d, "An info\n");
+ EINA_ERROR_PWARN_DOM(d, "A warning\n");
+ EINA_ERROR_PDBG_DOM(d, "A debug\n");
+
+ eina_error_shutdown();
+}
+END_TEST
+
+START_TEST(eina_error_domains_registry)
+{
+ fail_if(!eina_error_init());
+
+ int i;
+ int d[50];
+
+ for (i = 0; i < 50; i++)
+ {
+ d[i] = eina_error_domain_register("Test", EINA_COLOR_GREEN);
+ fail_if(d[i] < 0);
+ }
+
+ for (i = 0; i < 50; i++)
+ eina_error_domain_unregister(d[i]);
+
+ eina_error_shutdown();
+}
+END_TEST
+
+START_TEST(eina_error_domains_slot_reuse)
+{
+ fail_if(!eina_error_init());
+
+ // Create 9 domains
+ int idx[9];
+ int i;
+
+ for (i = 0; i < 9; i++)
+ {
+ idx[i] = eina_error_domain_register("Test1", EINA_COLOR_GREEN);
+ fail_if(idx[i] < 0);
+ }
+
+ // Slot 0 by default contains the global logger. The above code created
+ // domains for slots indexes from 1 to 9.
+ //
+ // The global logger allocated the first 8 initial slots. The 8th domain
+ // registered on the for loop will create 8 more slots.
+ //
+ // Test will just unregister a domain between 1 and 9 and assure that a new
+ // domain register will be placed on the available slot and not at the end.
+
+ int removed = idx[5];
+ eina_error_domain_unregister(removed);
+
+ int new = eina_error_domain_register("Test Slot", EINA_COLOR_GREEN);
+
+ // Check for slot reuse
+ fail_if(new != removed);
+
+ eina_error_shutdown();
+}
+END_TEST
+
+
void
eina_test_error(TCase *tc)
{
tcase_add_test(tc, eina_error_init_shutdown);
tcase_add_test(tc, eina_error_errno);
tcase_add_test(tc, eina_error_macro);
+ tcase_add_test(tc, eina_error_domains_macros);
+ tcase_add_test(tc, eina_error_domains_registry);
+ tcase_add_test(tc, eina_error_domains_slot_reuse);
}
Index: src/include/eina_error.h
===================================================================
--- src/include/eina_error.h (revision 41496)
+++ src/include/eina_error.h (working copy)
@@ -20,9 +20,18 @@
#define EINA_ERROR_H_
#include <stdarg.h>
+#include <stdint.h>
#include "eina_types.h"
+#define EINA_COLOR_RED "\033[31;1m"
+#define EINA_COLOR_BLUE "\033[34;1m"
+#define EINA_COLOR_GREEN "\033[32;1m"
+#define EINA_COLOR_YELLOW "\033[33;1m"
+#define EINA_COLOR_WHITE "\033[37;1m"
+#define EINA_COLOR_LIGHTBLUE "\033[36;1m"
+#define EINA_COLOR_NOTHING "\033[0m"
+
/**
* @addtogroup Eina_Tools_Group Tools
*
@@ -35,6 +44,18 @@
* @{
*/
+#define EINA_ERROR_PERR_DOM(DOM, fmt, ...) \
+ eina_error_dom_print(DOM, EINA_ERROR_LEVEL_ERR, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
+
+#define EINA_ERROR_PINFO_DOM(DOM, fmt, ...) \
+ eina_error_dom_print(DOM, EINA_ERROR_LEVEL_INFO, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
+
+#define EINA_ERROR_PDBG_DOM(DOM, fmt, ...) \
+ eina_error_dom_print(DOM, EINA_ERROR_LEVEL_DBG, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
+
+#define EINA_ERROR_PWARN_DOM(DOM, fmt, ...) \
+ eina_error_dom_print(DOM, EINA_ERROR_LEVEL_WARN, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
+
/**
* @def EINA_ERROR_PERR(fmt, ...)
* Print the error message described with the formatted string @a fmt
@@ -71,6 +92,19 @@
#define EINA_ERROR_PDBG(fmt, ...) \
eina_error_print(EINA_ERROR_LEVEL_DBG, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
+typedef struct _Eina_Error_Domain Eina_Error_Domain;
+
+struct _Eina_Error_Domain
+{
+ unsigned int level; /**< Max level to log */
+ const char *domain_str; /**< Formatted string with color to print */
+
+ /* Private */
+ Eina_Bool deleted:1; /**< Flags deletion of domain, a free slot */
+};
+
+
+
/**
* @typedef Eina_Error_Level
* List of available error levels.
@@ -82,11 +116,13 @@
*/
typedef enum _Eina_Error_Level
{
+ EINA_ERROR_LEVEL_CRITICAL, /**< Critical error level */
EINA_ERROR_LEVEL_ERR, /**< Error error level */
EINA_ERROR_LEVEL_WARN, /**< Warning error level */
EINA_ERROR_LEVEL_INFO, /**< Information error level */
EINA_ERROR_LEVEL_DBG, /**< Debug error level */
- EINA_ERROR_LEVELS /**< Count of error level */
+ EINA_ERROR_LEVELS, /**< Count of error level */
+ EINA_ERROR_LEVEL_UNKNOWN = INT32_MAX
} Eina_Error_Level;
/**
@@ -95,6 +131,7 @@
*/
typedef int Eina_Error;
+
/**
* @typedef Eina_Error_Print_Cb
* Type for print callbacks.
@@ -103,6 +140,10 @@
const char *fnc, int line, const char *fmt, void *data,
va_list args);
+typedef void (*Eina_Error_Dom_Print_Cb)(const Eina_Error_Domain *d, Eina_Error_Level level, const char *file,
+ const char *fnc, int line, const char *fmt, void *data,
+ va_list args);
+
/**
* @var EINA_ERROR_OUT_OF_MEMORY
* Error identifier corresponding to a lack of memory.
@@ -129,6 +170,13 @@
EAPI void eina_error_print_cb_set(Eina_Error_Print_Cb cb, void *data) EINA_ARG_NONNULL(1);
EAPI void eina_error_log_level_set(Eina_Error_Level level);
+EAPI int eina_error_domain_register(const char *name, const char *color) EINA_ARG_NONNULL(1);
+EAPI void eina_error_domain_unregister(int domain);
+
+EAPI void eina_error_dom_print(int domain, Eina_Error_Level level, const char *file, const char *function, int line, const char *fmt, ...) EINA_ARG_NONNULL(2, 3, 5);
+EAPI void eina_error_dom_print_cb_stdout(const Eina_Error_Domain *d, Eina_Error_Level level, const char *file, const char *fnc, int line, const char *fmt, void *data, va_list args);
+EAPI void eina_error_dom_print_cb_file(const Eina_Error_Domain *d, Eina_Error_Level level, const char *file, const char *fnc, int line, const char *fmt, void *data, va_list args);
+
/**
* @}
*/
Index: src/lib/eina_error.c
===================================================================
--- src/lib/eina_error.c (revision 41496)
+++ src/lib/eina_error.c (working copy)
@@ -380,32 +380,153 @@
* @cond LOCAL
*/
+#define EINA_ENV_ERROR_ABORT "EINA_ERROR_ABORT"
+#define EINA_ENV_ERROR_LEVEL "EINA_ERROR_LEVEL"
+#define EINA_ENV_ERROR_LEVELS "EINA_ERROR_LEVELS"
+#define EINA_ENV_COLOR_DISABLE "EINA_ERROR_COLOR_DISABLE"
+
+typedef struct _Eina_Error_Domain_Level_Pending Eina_Error_Domain_Level_Pending;
+struct _Eina_Error_Domain_Level_Pending
+{
+ EINA_INLIST;
+
+ unsigned int level;
+ char name[];
+};
+
static int _eina_error_init_count = 0;
+
+static int _disable_color = 0;
+
+/*
+ * List of domains registered
+ */
+static Eina_Error_Domain *_error_domains = NULL;
+static int _error_domains_count = 0;
+static int _error_domains_allocated = 0;
+
+/*
+ * List of levels for domains set by the user before the domains are registered,
+ * updates the domain levels on the first log and clears itself.
+ */
+static Eina_Inlist *_pending_list = NULL;
+
+/*
+ * List of errors registered
+ */
static Eina_Inlist *_error_list = NULL;
static int _error_list_count = 0;
static Eina_Error _err;
static Eina_Error_Print_Cb _print_cb = eina_error_print_cb_stdout;
+static Eina_Error_Dom_Print_Cb _dom_print_cb = eina_error_dom_print_cb_stdout;
static void *_print_cb_data = NULL;
-#define RED "\033[31;1m"
-#define GREEN "\033[32;1m"
-#define YELLOW "\033[33;1m"
-#define WHITE "\033[37;1m"
-#define NOTHING "\033[0m"
-
#ifdef DEBUG
static Eina_Error_Level _error_level = EINA_ERROR_LEVEL_DBG;
+#elif DEBUG_CRITICAL
+static Eina_Error_Level _error_level = EINA_ERROR_LEVEL_CRITICAL;
#else
static Eina_Error_Level _error_level = EINA_ERROR_LEVEL_ERR;
#endif
static const char *_colors[EINA_ERROR_LEVELS] = {
- RED, // EINA_ERROR_LEVEL_ERR
- YELLOW, // EINA_ERROR_LEVEL_WARN
- NOTHING, // EINA_ERROR_LEVEL_INFO
- GREEN, // EINA_ERROR_LEVEL_DBG
+ EINA_COLOR_YELLOW, // EINA_ERROR_LEVEL_CRITICAL
+ EINA_COLOR_RED, // EINA_ERROR_LEVEL_ERR
+ EINA_COLOR_YELLOW, // EINA_ERROR_LEVEL_WARN
+ EINA_COLOR_NOTHING, // EINA_ERROR_LEVEL_INFO
+ EINA_COLOR_GREEN, // EINA_ERROR_LEVEL_DBG
};
+static const char *
+eina_error_domain_str_get(const char *name, const char *color)
+{
+ const char *d;
+ int name_len;
+ int color_len;
+
+ if (color)
+ {
+ name_len = strlen(name);
+ color_len = strlen(color);
+ d = malloc(sizeof(char) * (color_len + name_len + strlen(EINA_COLOR_NOTHING) + 1));
+ memcpy((char *)d, color, color_len);
+ memcpy((char *)(d + color_len), name, name_len);
+ memcpy((char *)(d + color_len + name_len), EINA_COLOR_NOTHING, strlen(EINA_COLOR_NOTHING));
+ ((char *)d)[color_len + name_len + strlen(EINA_COLOR_NOTHING)] = '\0';
+ }
+ else
+ d = strdup(name);
+
+ return d;
+}
+
+static Eina_Error_Domain *
+eina_error_domain_new(Eina_Error_Domain *d, const char *name, const char *color)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(d, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
+
+ d->level = EINA_ERROR_LEVEL_UNKNOWN;
+ d->deleted = 0;
+
+ if (name)
+ {
+ if ((color) && (!_disable_color))
+ d->domain_str = eina_error_domain_str_get(name, color);
+ else
+ d->domain_str = eina_error_domain_str_get(name, NULL);
+ }
+ else
+ d->domain_str = NULL;
+
+ return d;
+}
+
+static void
+eina_error_domain_free(Eina_Error_Domain *d)
+{
+ EINA_SAFETY_ON_NULL_RETURN(d);
+
+ if (d->domain_str)
+ free((char *)d->domain_str);
+}
+
+static void eina_error_domain_parse_pendings(void)
+{
+ Eina_Error_Domain_Level_Pending *p;
+ char *l;
+ const char *start, *end;
+ char *tmp;
+
+ if (!(l = getenv(EINA_ENV_ERROR_LEVELS))) return;
+
+ // Form name:level,name1:level1,name2:level2,...
+ start = l;
+ while (1)
+ {
+ if (!start) break;
+ end = strchr(start, ':');
+ if (!end) break;
+
+ // Parse name
+ p = malloc(sizeof(Eina_Error_Domain_Level_Pending) + end - start);
+ memcpy((char *)p->name, start, end-start);
+ ((char *)p->name)[end - start] = '\0';
+
+ // Parse level
+ p->level = strtol((char *)(end + 1), &tmp, 10);
+
+ _pending_list = eina_inlist_append(_pending_list, EINA_INLIST_GET(p));
+
+ fprintf(stderr, "Parsed %s level %d\n", p->name, p->level);
+ if (!tmp) break;
+ start = strchr(tmp, ',');
+
+ if (start)
+ start += 1;
+ }
+}
+
/**
* @endcond
*/
@@ -490,6 +611,8 @@
EAPI Eina_Error EINA_ERROR_OUT_OF_MEMORY = 0;
+EAPI int EINA_ERROR_DOMAIN_GLOBAL = 0;
+
/**
* @endcond
*/
@@ -524,18 +647,36 @@
*/
EAPI int eina_error_init(void)
{
- if (!_eina_error_init_count)
- {
- char *level;
- /* TODO register the eina's basic errors */
- if ((level = getenv("EINA_ERROR_LEVEL")))
- {
- _error_level = atoi(level);
- }
- EINA_ERROR_OUT_OF_MEMORY = eina_error_msg_register("Out of memory");
- }
- /* get all the modules */
- return ++_eina_error_init_count;
+ if (_eina_error_init_count) return ++_eina_error_init_count;
+
+ char *level;
+ char *tmp;
+
+ // Check if color is disabled
+ if ((tmp = getenv(EINA_ENV_COLOR_DISABLE)) && (atoi(tmp) == 1))
+ _disable_color = 1;
+
+ if ((level = getenv(EINA_ENV_ERROR_LEVEL)))
+ _error_level = atoi(level);
+ else
+ _error_level = EINA_ERROR_LEVEL_ERR;
+
+ // TODO register the eina's basic errors */
+ EINA_ERROR_OUT_OF_MEMORY = eina_error_msg_register("Out of memory");
+
+ // Register UNKNOWN domain, the default logger
+ EINA_ERROR_DOMAIN_GLOBAL = eina_error_domain_register("", NULL);
+
+ if (EINA_ERROR_DOMAIN_GLOBAL < 0)
+ {
+ fprintf(stderr, "Failed to create global logging domain.\n");
+ return 0;
+ }
+
+ // Parse pending domains passed through EINA_ERROR_LEVELS
+ eina_error_domain_parse_pendings();
+
+ return ++_eina_error_init_count;
}
/**
@@ -554,35 +695,50 @@
*/
EAPI int eina_error_shutdown(void)
{
- Eina_Inlist *tmp;
+ if (_eina_error_init_count != 1) return --_eina_error_init_count;
- _eina_error_init_count--;
- if (!_eina_error_init_count)
- {
- /* remove the error strings */
- while (_error_list)
- {
- tmp = _error_list;
+ Eina_Inlist *tmp;
- _error_list = _error_list->next;
- free(tmp);
- }
- _error_list_count = 0;
- }
- return _eina_error_init_count;
+ /* remove the error strings */
+ while (_error_list)
+ {
+ tmp = _error_list;
+ _error_list = _error_list->next;
+ free(tmp);
+ }
+
+ _error_list_count = 0;
+
+ while (_error_domains_count--)
+ {
+ eina_error_domain_free(&_error_domains[_error_domains_count]);
+ }
+
+ free(_error_domains);
+
+ _error_domains = NULL;
+
+ while (_pending_list)
+ {
+ tmp = _pending_list;
+ _pending_list = _pending_list->next;
+ free(tmp);
+ }
+
+ return --_eina_error_init_count;
}
/**
- * @brief Register a new error type.
- *
- * @param msg The description of the error.
- * @return The unique number identifier for this error.
- *
- * This function stores in a list the error message described by
- * @p msg. The returned value is a unique identifier greater or equal
- * than 1. The description can be retrieve later by passing to
- * eina_error_msg_get() the returned value.
- */
+* @brief Register a new error type.
+*
+* @param msg The description of the error.
+* @return The unique number identifier for this error.
+*
+* This function stores in a list the error message described by
+* @p msg. The returned value is a unique identifier greater or equal
+* than 1. The description can be retrieve later by passing to
+* eina_error_msg_get() the returned value.
+*/
EAPI Eina_Error eina_error_msg_register(const char *msg)
{
Eina_Inlist *tmp;
@@ -696,7 +852,8 @@
_print_cb(level, file, fnc, line, fmt, _print_cb_data, args);
va_end(args);
- if (getenv("EINA_ERROR_ABORT")) abort();
+ if ((getenv(EINA_ENV_ERROR_ABORT) && level <= EINA_ERROR_LEVEL_ERR))
+ abort();
}
EAPI void eina_error_vprint(Eina_Error_Level level, const char *file,
@@ -711,7 +868,8 @@
_print_cb(level, file, fnc, line, fmt, _print_cb_data, args);
- if (getenv("EINA_ERROR_ABORT")) abort();
+ if ((getenv(EINA_ENV_ERROR_ABORT) && level <= EINA_ERROR_LEVEL_ERR))
+ abort();
}
/**
@@ -733,10 +891,7 @@
const char *fnc, int line, const char *fmt, __UNUSED__ void *data,
va_list args)
{
- printf("%s", _colors[level]);
- printf("[%s:%d] %s() ", file, line, fnc);
- printf("%s", _colors[EINA_ERROR_LEVEL_INFO]);
- vprintf(fmt, args);
+ eina_error_dom_print_cb_stdout(&_error_domains[0], level, file, fnc, line, fmt, data, args);
}
/**
@@ -760,10 +915,7 @@
const char *fnc, int line, const char *fmt, void *data,
va_list args)
{
- FILE *f = data;
-
- fprintf(f, "[%s:%d] %s() ", file, line, fnc);
- vfprintf(f, fmt, args);
+ eina_error_dom_print_cb_file(&_error_domains[0], level, file, fnc, line, fmt, data, args);
}
/**
@@ -795,6 +947,143 @@
_error_level = level;
}
+/*
+ * @param name Domain name
+ * @param color Color of the domain name
+ *
+ * @return Domain index that will be used as the DOMAIN parameter on log
+ * macros. A negative return value means an error ocurred.
+ */
+EAPI int
+eina_error_domain_register(const char *name, const char *color)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(name, 0);
+
+ Eina_Error_Domain_Level_Pending *pending = NULL;
+ int i;
+
+ for (i = 0; i < _error_domains_count; i++)
+ {
+ if (_error_domains[i].deleted)
+ {
+ // Found a flagged slot, free domain_str and replace slot
+ fprintf(stderr, "Found a deleted flag slot at %d\n", i);
+ eina_error_domain_free(&_error_domains[i]);
+ eina_error_domain_new(&_error_domains[i], name, color);
+ goto finish_register;
+ }
+ }
+
+ if (_error_domains_count >= _error_domains_allocated)
+ {
+ fprintf(stderr, "No free slots, alocating more.\n");
+ // Did not found a slot, realloc 8 more slots. Also works on the first time
+ // when the array doesn't exist yet.
+ Eina_Error_Domain *tmp = _error_domains;
+
+ _error_domains_allocated += 8;
+ _error_domains = realloc(_error_domains, sizeof(Eina_Error_Domain)*_error_domains_allocated);
+
+ fprintf(stderr, "After realloc call\n");
+
+ if (!_error_domains)
+ {
+ fprintf(stderr, "Could not alloc more domains.\n");
+ _error_domains = tmp;
+ _error_domains_allocated -= 8;
+ return -1;
+ }
+
+ fprintf(stderr, "Allocated successfully, alloc count is now %d\n", _error_domains_allocated);
+ }
+
+ // Use an allocated slot
+ eina_error_domain_new(&_error_domains[i], name, color);
+
+finish_register:
+
+ EINA_INLIST_FOREACH(_pending_list, pending)
+ {
+ if (!strcmp(pending->name, name))
+ {
+ fprintf(stderr, "Updating domain %s level from %d to %d\n", name, _error_domains[i].level, pending->level);
+ _error_domains[i].level = pending->level;
+ _pending_list = eina_inlist_remove(_pending_list, EINA_INLIST_GET(pending));
+ free(pending);
+ break;
+ }
+ }
+
+ // Check if level is still UNKNOWN, set it to global
+ if (_error_domains[i].level == EINA_ERROR_LEVEL_UNKNOWN)
+ _error_domains[i].level = _error_level;
+
+ _error_domains_count += 1;
+ return i;
+}
+
+EAPI void
+eina_error_domain_unregister(int domain)
+{
+ if (domain >= _error_domains_count) return;
+
+ Eina_Error_Domain *d = &_error_domains[domain];
+ d->deleted = 1;
+}
+
+EAPI void
+eina_error_dom_print_cb_stdout(const Eina_Error_Domain *d, Eina_Error_Level level,
+ const char *file, const char *fnc, int line, const char *fmt,
+ __UNUSED__ void *data, va_list args)
+{
+ EINA_SAFETY_ON_NULL_RETURN(d);
+
+ printf("%s %s%s:%d %s()%s ", d->domain_str,
+ (!_disable_color) ? _colors[level] : "",
+ file, line, fnc,
+ (!_disable_color) ? EINA_COLOR_NOTHING: "");
+ vprintf(fmt, args);
+}
+
+EAPI void
+eina_error_dom_print_cb_file(const Eina_Error_Domain *d, __UNUSED__ Eina_Error_Level level,
+ const char *file, const char *fnc, int line, const char *fmt,
+ void *data, va_list args)
+{
+ EINA_SAFETY_ON_NULL_RETURN(file);
+ EINA_SAFETY_ON_NULL_RETURN(fnc);
+ EINA_SAFETY_ON_NULL_RETURN(fmt);
+
+ FILE *f = data;
+ fprintf(f, "%s %s:%d %s() ", d->domain_str, file, line, fnc);
+ vfprintf(f, fmt, args);
+}
+
+EAPI void
+eina_error_dom_print(int domain, Eina_Error_Level level, const char *file,
+ const char *fnc, int line, const char *fmt, ...)
+{
+ EINA_SAFETY_ON_NULL_RETURN(file);
+ EINA_SAFETY_ON_NULL_RETURN(fnc);
+ EINA_SAFETY_ON_NULL_RETURN(fmt);
+
+ if (domain >= _error_domains_count) return;
+ if (domain < 0) return;
+
+ Eina_Error_Domain *d = &_error_domains[domain];
+
+ if (level > d->level) return;
+
+ va_list args;
+
+ va_start(args, fmt);
+ _dom_print_cb(d, level, file, fnc, line, fmt, _print_cb_data, args);
+ va_end(args);
+
+ if ((getenv(EINA_ENV_ERROR_ABORT) && level <= EINA_ERROR_LEVEL_ERR))
+ abort();
+}
+
/**
* @}
*/
------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now. http://p.sf.net/sfu/bobj-july
_______________________________________________
enlightenment-devel mailing list
enlightenment-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel