Removing workaround with unused variable..
On Sat, Jul 25, 2009 at 10:30 PM, Andre Dieb
<[email protected]>wrote:
> Fix a missing free() spotted by Sachiel.
>
>
> On Sat, Jul 25, 2009 at 9:21 PM, Andre Dieb
> <[email protected]>wrote:
>
>> The new patch is attached (hope it works now).
>>
>>
>> On Sat, Jul 25, 2009 at 9:04 PM, Andre Dieb <[email protected]
>> > wrote:
>>
>>> The new patch is attached.
>>>
>>> On Sat, Jul 18, 2009 at 1:57 PM, Gustavo Sverzut Barbieri
>>> <[email protected]> wrote:
>>>
>>>> On Fri, Jul 17, 2009 at 6:55 PM, Andre Dieb<
>>>> [email protected]> 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: [email protected]
>>>> 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/
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,150 @@
* @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, ',');
+ }
+}
+
/**
* @endcond
*/
@@ -490,6 +608,8 @@
EAPI Eina_Error EINA_ERROR_OUT_OF_MEMORY = 0;
+EAPI int EINA_ERROR_DOMAIN_GLOBAL = 0;
+
/**
* @endcond
*/
@@ -524,18 +644,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 +692,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 +849,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 +865,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 +888,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 +912,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 +944,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();
+}
+
/**
* @}
*/
------------------------------------------------------------------------------
_______________________________________________
enlightenment-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel